From 7596d87bb4cf11efcc6474e85becaa8cd6f3bfa8 Mon Sep 17 00:00:00 2001 From: UnKownOwO <80520429@qq.com> Date: Thu, 5 Jan 2023 23:41:24 +0800 Subject: [PATCH] =?UTF-8?q?GCG=E8=BF=9B=E5=85=A5=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gs/game/gcg_manager.go | 385 +++++++++++++++-- gs/game/user_gcg.go | 594 +++++++++++---------------- gs/model/player.go | 2 +- protocol/cmd/cmd_id_proto_obj_map.go | 1 + 4 files changed, 595 insertions(+), 387 deletions(-) diff --git a/gs/game/gcg_manager.go b/gs/game/gcg_manager.go index f0da80c9..0c98b6ef 100644 --- a/gs/game/gcg_manager.go +++ b/gs/game/gcg_manager.go @@ -2,6 +2,8 @@ package game import ( "hk4e/gs/model" + "hk4e/pkg/logger" + "hk4e/protocol/proto" ) // ControllerType 操控者类型 @@ -24,26 +26,24 @@ type GCGCardInfo struct { isShow bool // 是否展示 } +type ControllerLoadState uint8 + +const ( + ControllerLoadState_None ControllerLoadState = iota + ControllerLoadState_AskDuel + ControllerLoadState_InitFinish +) + // GCGController 操控者 type GCGController struct { controllerId uint32 // 操控者Id cardMap map[uint32]*GCGCardInfo // 卡牌列表 + loadState ControllerLoadState // 加载状态 controllerType ControllerType // 操控者的类型 player *model.Player ai uint32 // 暂时不写 } -// GCGGame 游戏对局 -type GCGGame struct { - guid uint32 // 唯一Id - gameId uint32 // 游戏Id - round uint32 // 游戏回合数 - serverSeqCounter uint32 // 请求序列生成计数器 - controllerIdCounter uint32 // 操控者Id生成器 - cardGuidCounter uint32 // 卡牌guid生成计数器 - controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId -} - // GCGManager 七圣召唤管理器 type GCGManager struct { gameMap map[uint32]*GCGGame // 游戏列表 uint32 -> guid @@ -57,32 +57,365 @@ func NewGCGManager() *GCGManager { } // CreateGame 创建GCG游戏对局 -func (g *GCGManager) CreateGame(gameId uint32) *GCGGame { +func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGGame { g.gameGuidCounter++ game := &GCGGame{ - guid: g.gameGuidCounter, - gameId: gameId, - round: 1, - controllerMap: make(map[uint32]*GCGController, 0), + guid: g.gameGuidCounter, + gameId: gameId, + roundInfo: &GCGRoundInfo{ + roundNum: 1, // 默认以第一回合开始 + allowControllerMap: make(map[uint32]uint32, 0), + firstController: 1, // 1号操控者为先手 + }, + controllerMap: make(map[uint32]*GCGController, 0), + controllerMsgPackMap: make(map[uint32][]*proto.GCGMessagePack), + historyCardList: make([]*proto.GCGCard, 0, 0), + historyMsgPackList: make([]*proto.GCGMessagePack, 0, 0), } + // 初始化游戏 + game.InitGame(playerList) // 记录游戏 g.gameMap[game.guid] = game return game } -// JoinGame 玩家加入GCG游戏 -func (g *GCGManager) JoinGame(game *GCGGame, player *model.Player) { - game.controllerIdCounter++ +// GCGMsgPhaseChange GCG消息阶段改变 +func (g *GCGManager) GCGMsgPhaseChange(game *GCGGame, afterPhase proto.GCGPhaseType) *proto.GCGMessage { + gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{ + BeforePhase: game.roundInfo.phaseType, + AfterPhase: afterPhase, + AllowControllerMap: make([]*proto.Uint32Pair, 0, len(game.controllerMap)), + } + // 开始阶段所有玩家允许操作 + if afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_START || afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE || afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_MAIN { + for controllerId := range game.controllerMap { + gcgMsgPhaseChange.AllowControllerMap = append(gcgMsgPhaseChange.AllowControllerMap, &proto.Uint32Pair{ + Key: controllerId, + Value: 1, + }) + } + } + gcgMessage := &proto.GCGMessage{ + Message: &proto.GCGMessage_PhaseChange{ + PhaseChange: gcgMsgPhaseChange, + }, + } + // 修改游戏的阶段状态 + game.roundInfo.phaseType = afterPhase + return gcgMessage +} + +// GCGMsgPhaseContinue GCG消息阶段跳过 +func (g *GCGManager) GCGMsgPhaseContinue() *proto.GCGMessage { + gcgMsgPhaseContinue := &proto.GCGMsgPhaseContinue{} + gcgMessage := &proto.GCGMessage{ + Message: &proto.GCGMessage_PhaseContinue{ + PhaseContinue: gcgMsgPhaseContinue, + }, + } + return gcgMessage +} + +// GCGMsgUpdateController GCG消息更新操控者 +func (g *GCGManager) GCGMsgUpdateController(game *GCGGame) *proto.GCGMessage { + gcgMsgUpdateController := &proto.GCGMsgUpdateController{ + AllowControllerMap: make([]*proto.Uint32Pair, 0, len(game.controllerMap)), + } + // 操控者的允许次数 + for controllerId, _ := range game.roundInfo.allowControllerMap { + gcgMsgUpdateController.AllowControllerMap = append(gcgMsgUpdateController.AllowControllerMap, &proto.Uint32Pair{ + Key: controllerId, + Value: 0, + }) + } + gcgMessage := &proto.GCGMessage{ + Message: &proto.GCGMessage_UpdateController{ + UpdateController: gcgMsgUpdateController, + }, + } + return gcgMessage +} + +// GCGMsgClientPerform GCG消息客户端执行 +func (g *GCGManager) GCGMsgClientPerform(performType proto.GCGClientPerformType, paramList []uint32) *proto.GCGMessage { + gcgMsgClientPerform := &proto.GCGMsgClientPerform{ + ParamList: paramList, + PerformType: performType, + } + gcgMessage := &proto.GCGMessage{ + Message: &proto.GCGMessage_ClientPerform{ + ClientPerform: gcgMsgClientPerform, + }, + } + return gcgMessage +} + +// GCGRoundInfo 游戏对局回合信息 +type GCGRoundInfo struct { + roundNum uint32 // 游戏当前回合数 + phaseType proto.GCGPhaseType // 现在所处的阶段类型 + allowControllerMap map[uint32]uint32 // 回合内操控者允许的次数 + firstController uint32 // 当前回合先手的操控者 +} + +// GCGGame 游戏对局 +type GCGGame struct { + guid uint32 // 唯一Id + gameId uint32 // 游戏Id + serverSeqCounter uint32 // 请求序列生成计数器 + controllerIdCounter uint32 // 操控者Id生成器 + cardGuidCounter uint32 // 卡牌guid生成计数器 + roundInfo *GCGRoundInfo // 游戏回合信息 + controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId + controllerMsgPackMap map[uint32][]*proto.GCGMessagePack // 操控者消息包待发送区 0代表全局 + // TODO 游戏重连 + historyCardList []*proto.GCGCard // 历史发送的卡牌 + historyMsgPackList []*proto.GCGMessagePack // 历史发送的消息包 +} + +// AddPlayer GCG游戏添加玩家 +func (g *GCGGame) AddPlayer(player *model.Player) { + // 创建操控者 + g.controllerIdCounter++ controller := &GCGController{ - controllerId: game.controllerIdCounter, + controllerId: g.controllerIdCounter, cardMap: make(map[uint32]*GCGCardInfo, 0), + loadState: ControllerLoadState_None, controllerType: ControllerType_Player, player: player, } // 生成卡牌信息 - + g.cardGuidCounter++ + controller.cardMap[1301] = &GCGCardInfo{ + cardId: 1301, + guid: g.cardGuidCounter, + faceType: 0, + tagList: []uint32{203, 303, 401}, + tokenMap: map[uint32]uint32{ + 1: 10, + 2: 10, + 4: 0, + 5: 3, + }, + skillIdList: []uint32{ + 13011, + 13012, + 13013, + }, + skillLimitList: []uint32{}, + isShow: true, + } + g.cardGuidCounter++ + controller.cardMap[1103] = &GCGCardInfo{ + cardId: 1103, + guid: g.cardGuidCounter, + faceType: 0, + tagList: []uint32{201, 301, 401}, + tokenMap: map[uint32]uint32{ + 1: 10, // 血量 + 2: 10, // 最大血量(不确定) + 4: 0, // 充能 + 5: 2, // 充能条 + }, + skillIdList: []uint32{ + 11031, + 11032, + 11033, + }, + skillLimitList: []uint32{}, + isShow: true, + } + g.cardGuidCounter++ + controller.cardMap[3001] = &GCGCardInfo{ + cardId: 3001, + guid: g.cardGuidCounter, + faceType: 0, + tagList: []uint32{200, 300, 502, 503}, + tokenMap: map[uint32]uint32{ + 1: 4, + 2: 4, + 4: 0, + 5: 2, + }, + skillIdList: []uint32{ + 30011, + 30012, + 30013, + }, + skillLimitList: []uint32{}, + isShow: true, + } + // g.cardGuidCounter++ + // controller.cardMap[1301011] = &GCGCardInfo{ + // cardId: 1301011, + // guid: g.cardGuidCounter, + // faceType: 0, + // skillIdList: []uint32{ + // 13010111, + // }, + // skillLimitList: []uint32{}, + // isShow: true, + // } // 记录操控者 - game.controllerMap[game.controllerIdCounter] = controller + g.controllerMap[g.controllerIdCounter] = controller + player.GCGCurGameGuid = g.guid +} + +// AddAI GCG游戏添加AI +func (g *GCGGame) AddAI() { + // 创建操控者 + g.controllerIdCounter++ + controller := &GCGController{ + controllerId: g.controllerIdCounter, + cardMap: make(map[uint32]*GCGCardInfo, 0), + loadState: ControllerLoadState_InitFinish, + controllerType: ControllerType_AI, + ai: 233, + } + // 生成卡牌信息 + g.cardGuidCounter++ + controller.cardMap[3001] = &GCGCardInfo{ + cardId: 3001, + guid: g.cardGuidCounter, + faceType: 0, + tagList: []uint32{200, 300, 502, 503}, + tokenMap: map[uint32]uint32{ + 1: 4, + 2: 4, + 4: 0, + 5: 2, + }, + skillIdList: []uint32{ + 30011, + 30012, + 30013, + }, + skillLimitList: []uint32{}, + isShow: true, + } + g.cardGuidCounter++ + controller.cardMap[3302] = &GCGCardInfo{ + cardId: 3302, + guid: g.cardGuidCounter, + faceType: 0, + tagList: []uint32{200, 303, 502, 503}, + tokenMap: map[uint32]uint32{ + 1: 8, + 2: 8, + 4: 0, + 5: 2, + }, + skillIdList: []uint32{ + 33021, + 33022, + 33023, + 33024, + }, + skillLimitList: []uint32{}, + isShow: true, + } + // 记录操控者 + g.controllerMap[g.controllerIdCounter] = controller +} + +// InitGame 初始化GCG游戏 +func (g *GCGGame) InitGame(playerList []*model.Player) { + // 初始化玩家 + for _, player := range playerList { + g.AddPlayer(player) + } + // 添加AI + g.AddAI() + + // 初始化每个操控者的次数 + for controllerId := range g.controllerMap { + g.roundInfo.allowControllerMap[controllerId] = 0 + } + // 先手者操控数为1 + g.roundInfo.allowControllerMap[g.roundInfo.firstController] = 1 + + // TODO 验证玩家人数是否符合 + // 预开始游戏 + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_START), GCG_MANAGER.GCGMsgUpdateController(g)) + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, GCG_MANAGER.GCGMsgPhaseContinue()) + g.SendMessagePack(0) + // 预开始游戏后 ServerSeq 会跟官服不同 这里重置一下 + g.serverSeqCounter = 0 + logger.Error("gcg init") +} + +// StartGame 开始GCG游戏 +func (g *GCGGame) StartGame() { + // 开始游戏消息包 + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, GCG_MANAGER.GCGMsgUpdateController(g)) + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_PHASE_EXIT, GCG_MANAGER.GCGMsgClientPerform(proto.GCGClientPerformType_GCG_CLIENT_PERFORM_TYPE_FIRST_HAND, []uint32{g.roundInfo.firstController})) + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW)) + g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE)) + g.SendMessagePack(0) + logger.Error("gcg start") +} + +// CheckAllInitFinish 检查所有玩家是否加载完成 +func (g *GCGGame) CheckAllInitFinish() { + // 检查所有玩家是否加载完成 + for _, controller := range g.controllerMap { + if controller.loadState != ControllerLoadState_InitFinish { + return + } + } + // TODO 可能会玩家中途退了 超时结束游戏 + // 正式开始游戏 + g.StartGame() +} + +// AddMessagePack 添加操控者的待发送区GCG消息 +func (g *GCGGame) AddMessagePack(controllerId uint32, actionType proto.GCGActionType, msgList ...*proto.GCGMessage) { + _, ok := g.controllerMsgPackMap[controllerId] + if !ok { + g.controllerMsgPackMap[controllerId] = make([]*proto.GCGMessagePack, 0, len(msgList)*5) + } + pack := &proto.GCGMessagePack{ + ActionType: actionType, + MsgList: make([]*proto.GCGMessage, 0, len(msgList)), + ControllerId: controllerId, + } + // 将每个GCG消息添加进消息包中 + for _, message := range msgList { + pack.MsgList = append(pack.MsgList, message) + } + // 将消息包添加进待发送区 + g.controllerMsgPackMap[controllerId] = append(g.controllerMsgPackMap[controllerId], pack) +} + +// SendMessagePack 发送操控者的待发送区GCG消息 +func (g *GCGGame) SendMessagePack(controllerId uint32) { + msgPackList, ok := g.controllerMsgPackMap[controllerId] + if !ok { + logger.Error("msg pack list error, controllerId: %v", controllerId) + return + } + // 0代表广播给全体玩家 + if controllerId == 0 { + g.serverSeqCounter++ + for _, controller := range g.controllerMap { + GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, msgPackList) + } + } else { + // 获取指定的操控者 + controller, ok := g.controllerMap[controllerId] + if !ok { + logger.Error("controller is nil, controllerId: %v", controllerId) + return + } + g.serverSeqCounter++ + GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, msgPackList) + } + // 记录发送的历史消息包 + for _, pack := range msgPackList { + g.historyMsgPackList = append(g.historyMsgPackList, pack) + } + // 清空待发送区的数据 + g.controllerMsgPackMap[controllerId] = make([]*proto.GCGMessagePack, 0, len(msgPackList)) } // // CreateGameCardInfo 生成操控者卡牌信息 @@ -90,12 +423,12 @@ func (g *GCGManager) JoinGame(game *GCGGame, player *model.Player) { // // } -// GetGameControllerByUserId 通过玩家Id获取GCGController对象 -func (g *GCGManager) GetGameControllerByUserId(game *GCGGame, userId uint32) *GCGController { - for _, controller := range game.controllerMap { +// GetControllerByUserId 通过玩家Id获取GCGController对象 +func (g *GCGGame) GetControllerByUserId(userId uint32) *GCGController { + for _, controller := range g.controllerMap { // 为nil说明该操控者不是玩家 if controller.player == nil { - return nil + continue } if controller.player.PlayerID == userId { return controller diff --git a/gs/game/user_gcg.go b/gs/game/user_gcg.go index 80a015b1..ca3cfedb 100644 --- a/gs/game/user_gcg.go +++ b/gs/game/user_gcg.go @@ -28,11 +28,12 @@ func (g *GameManager) GCGLogin(player *model.Player) { // GCGTavernInit GCG酒馆初始化 func (g *GameManager) GCGTavernInit(player *model.Player) { - // // GCG酒馆信息通知 - // g.SendMsg(cmd.GCGTCTavernInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTCTavernInfoNotify(player)) - // // GCG酒馆NPC信息通知 - // g.SendMsg(cmd.GCGTavernNpcInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTavernNpcInfoNotify(player)) - // 可能是包没发全导致卡进度条? + if player.SceneId == 1076 { + // GCG酒馆信息通知 + g.SendMsg(cmd.GCGTCTavernInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTCTavernInfoNotify(player)) + // GCG酒馆NPC信息通知 + g.SendMsg(cmd.GCGTavernNpcInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTavernNpcInfoNotify(player)) + } } // GCGStartChallenge GCG开始挑战 @@ -48,8 +49,11 @@ func (g *GameManager) GCGStartChallenge(player *model.Player) { // } // g.SendMsg(cmd.GCGStartChallengeByCheckRewardRsp, player.PlayerID, player.ClientSeq, gcgStartChallengeByCheckRewardRsp) + // 创建GCG游戏 + game := GCG_MANAGER.CreateGame(30101, []*model.Player{player}) + // GCG游戏简要信息通知 - GAME_MANAGER.SendMsg(cmd.GCGGameBriefDataNotify, player.PlayerID, player.ClientSeq, g.PacketGCGGameBriefDataNotify(player, proto.GCGGameBusinessType_GCG_GAME_BUSINESS_TYPE_GUIDE_GROUP, 30102)) + GAME_MANAGER.SendMsg(cmd.GCGGameBriefDataNotify, player.PlayerID, player.ClientSeq, g.PacketGCGGameBriefDataNotify(player, proto.GCGGameBusinessType_GCG_GAME_BUSINESS_TYPE_GUIDE_GROUP, game)) // 玩家进入GCG界面 g.TeleportPlayer(player, constant.EnterReasonConst.DungeonEnter, 79999, new(model.Vector), 2162) @@ -63,388 +67,258 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message) g.CommonRetError(cmd.GCGAskDuelRsp, player, &proto.GCGAskDuelRsp{}, proto.Retcode_RET_GCG_GAME_NOT_RUNNING) return } - // 计数器+1 - game.serverSeqCounter++ // 获取玩家的操控者对象 - gameController := GCG_MANAGER.GetGameControllerByUserId(game, player.PlayerID) + gameController := game.GetControllerByUserId(player.PlayerID) if gameController == nil { g.CommonRetError(cmd.GCGAskDuelRsp, player, &proto.GCGAskDuelRsp{}, proto.Retcode_RET_GCG_NOT_IN_GCG_DUNGEON) return } + + // 更改操控者加载状态 + gameController.loadState = ControllerLoadState_AskDuel + + // 计数器+1 + game.serverSeqCounter++ // PacketGCGAskDuelRsp - // gcgAskDuelRsp := &proto.GCGAskDuelRsp{ - // Duel: &proto.GCGDuel{ - // ServerSeq: game.serverSeqCounter, - // ShowInfoList: make([]*proto.GCGControllerShowInfo, 0, len(game.controllerMap)), - // ForbidFinishChallengeList: nil, - // CardList: nil, - // Unk3300_BIANMOPDEHO: 0, - // CostRevise: nil, - // GameId: game.gameId, - // FieldList: nil, - // Unk3300_CDCMBOKBLAK: nil, - // BusinessType: 0, - // IntentionList: nil, - // ChallengeList: nil, - // HistoryCardList: nil, - // Round: game.round, - // ControllerId: gameController.controllerId, - // HistoryMsgPackList: nil, - // Unk3300_JHDDNKFPINA: 0, - // CardIdList: make([]uint32, 0, 0), - // Unk3300_JBBMBKGOONO: 0, - // Phase: nil, - // }, - // } - // // 玩家信息列表 - // for _, controller := range game.controllerMap { - // gcgControllerShowInfo := &proto.GCGControllerShowInfo{ - // ControllerId: controller.controllerId, - // ProfilePicture: &proto.ProfilePicture{}, - // } - // // 如果为玩家则更改为玩家信息 - // if controller.controllerType == ControllerType_Player { - // gcgControllerShowInfo.ProfilePicture.AvatarId = player.HeadImage - // gcgControllerShowInfo.ProfilePicture.AvatarId = player.AvatarMap[player.HeadImage].Costume - // } - // gcgAskDuelRsp.Duel.ShowInfoList = append(gcgAskDuelRsp.Duel.ShowInfoList) - // } - // GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp) - // PacketGCGAskDuelRsp - gcgAskDuelRsp := new(proto.GCGAskDuelRsp) - gcgAskDuelRsp.Duel = &proto.GCGDuel{ - ServerSeq: 1, // 应该每次+1 - ShowInfoList: []*proto.GCGControllerShowInfo{ - // 玩家的 - { - // PsnId: ? - NickName: player.NickName, - // OnlineId: ? - ProfilePicture: &proto.ProfilePicture{ - AvatarId: player.TeamConfig.GetActiveAvatarId(), - CostumeId: player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Costume, + gcgAskDuelRsp := &proto.GCGAskDuelRsp{ + Duel: &proto.GCGDuel{ + ServerSeq: game.serverSeqCounter, + // ShowInfoList 游戏内显示双方头像名字 + ShowInfoList: make([]*proto.GCGControllerShowInfo, 0, len(game.controllerMap)), + ForbidFinishChallengeList: nil, + // CardList 卡牌列表 + CardList: make([]*proto.GCGCard, 0, 0), + Unk3300_BIANMOPDEHO: 1, // Unk + CostRevise: &proto.GCGCostReviseInfo{ // 暂无数据 + CanUseHandCardIdList: nil, + SelectOnStageCostList: nil, + PlayCardCostList: nil, + AttackCostList: nil, + IsCanAttack: false, + }, + GameId: 0, // 官服是0 + // FieldList 玩家牌盒信息 卡牌显示相关 + FieldList: make([]*proto.GCGPlayerField, 0, len(game.controllerMap)), + Unk3300_CDCMBOKBLAK: make([]*proto.Unk3300_ADHENCIFKNI, 0, len(game.controllerMap)), + BusinessType: 0, + IntentionList: nil, // empty + // ChallengeList 可能是挑战目标 + ChallengeList: []*proto.GCGDuelChallenge{ + // TODO 暂时写死 + { + ChallengeId: 1, + CurProgress: 906, + TotalProgress: 0, }, - ControllerId: 1, - }, - // 对手的 - { - ProfilePicture: &proto.ProfilePicture{}, - ControllerId: 2, - }, - }, - // ForbidFinishChallengeList: nil, - CardList: []*proto.GCGCard{ - { - TagList: []uint32{203, 303, 401}, - Guid: 1, // 应该每次+1 - IsShow: true, - TokenList: []*proto.GCGToken{ - { - Key: 1, - Value: 10, - }, - { - Key: 2, - Value: 10, - }, - { - Key: 4, - }, - { - Key: 5, - Value: 3, - }, + { + ChallengeId: 1, + CurProgress: 907, + TotalProgress: 0, }, - // FaceType: 0, ? - SkillIdList: []uint32{13011, 13012, 13013}, - // SkillLimitsList: nil, - Id: 1301, - ControllerId: 1, - }, - { - TagList: []uint32{201, 301, 401}, - Guid: 2, // 应该每次+1 - IsShow: true, - TokenList: []*proto.GCGToken{ - { - Key: 1, - Value: 10, - }, - { - Key: 2, - Value: 10, - }, - { - Key: 4, - }, - { - Key: 5, - Value: 2, - }, + { + ChallengeId: 1, + CurProgress: 901, + TotalProgress: 0, }, - // FaceType: 0, ? - SkillIdList: []uint32{11031, 11032, 11033}, - // SkillLimitsList: nil, - Id: 1103, - ControllerId: 1, - }, - { - TagList: []uint32{200, 300, 502, 503}, - Guid: 3, // 应该每次+1 - IsShow: true, - TokenList: []*proto.GCGToken{ - { - Key: 1, - Value: 4, - }, - { - Key: 2, - Value: 4, - }, - { - Key: 4, - }, - { - Key: 5, - Value: 2, - }, + { + ChallengeId: 1, + CurProgress: 903, + TotalProgress: 0, }, - // FaceType: 0, ? - SkillIdList: []uint32{30011, 30012, 30013}, - // SkillLimitsList: nil, - Id: 3301, - ControllerId: 2, - }, - { - TagList: []uint32{200, 303, 502, 503}, - Guid: 4, // 应该每次+1 - IsShow: true, - TokenList: []*proto.GCGToken{ - { - Key: 1, - Value: 8, - }, - { - Key: 2, - Value: 8, - }, - { - Key: 4, - }, - { - Key: 5, - Value: 2, - }, + { + ChallengeId: 1, + CurProgress: 904, + TotalProgress: 0, }, - // FaceType: 0, ? - SkillIdList: []uint32{33021, 33022, 33023, 33024}, - // SkillLimitsList: nil, - Id: 3302, - ControllerId: 2, - }, - { - Guid: 5, // 应该每次+1 - IsShow: true, - SkillIdList: []uint32{13010111}, - Id: 1301011, - ControllerId: 1, - }, - }, - Unk3300_BIANMOPDEHO: 1, - CostRevise: &proto.GCGCostReviseInfo{ - CanUseHandCardIdList: nil, - SelectOnStageCostList: nil, - PlayCardCostList: nil, - AttackCostList: nil, - IsCanAttack: false, - }, - // GameId: 0, - FieldList: []*proto.GCGPlayerField{ - { - // Unk3300_IKJMGAHCFPM: 0, - ModifyZoneMap: map[uint32]*proto.GCGZone{ - 1: {}, - 2: {}, + { + ChallengeId: 1, + CurProgress: 905, + TotalProgress: 0, }, - // Unk3300_GGHKFFADEAL: 0, - Unk3300_AOPJIOHMPOF: nil, - Unk3300_FDFPHNDOJML: 0, - Unk3300_IPLMHKCNDLE: &proto.GCGZone{}, - Unk3300_EIHOMDLENMK: &proto.GCGZone{}, - // WaitingList: nil, - // Unk3300_PBECINKKHND: 0, - ControllerId: 1, - Unk3300_INDJNJJJNKL: &proto.GCGZone{ - CardList: []uint32{1, 2}, + { + ChallengeId: 1, + CurProgress: 908, + TotalProgress: 0, }, - Unk3300_EFNAEFBECHD: &proto.GCGZone{}, - // IsPassed: false, - // IntentionList: nil, - // DiceSideList: nil, - // DeckCardNum: 0, - // Unk3300_GLNIFLOKBPM: 0, - }, - { - // Unk3300_IKJMGAHCFPM: 0, - ModifyZoneMap: map[uint32]*proto.GCGZone{ - 3: {}, - 4: {}, - }, - // Unk3300_GGHKFFADEAL: 0, - Unk3300_AOPJIOHMPOF: nil, - Unk3300_FDFPHNDOJML: 0, - Unk3300_IPLMHKCNDLE: &proto.GCGZone{}, - Unk3300_EIHOMDLENMK: &proto.GCGZone{}, - // WaitingList: nil, - // Unk3300_PBECINKKHND: 0, - ControllerId: 2, - Unk3300_INDJNJJJNKL: &proto.GCGZone{ - CardList: []uint32{3, 4}, - }, - Unk3300_EFNAEFBECHD: &proto.GCGZone{}, - // IsPassed: false, - // IntentionList: nil, - // DiceSideList: nil, - // DeckCardNum: 0, - // Unk3300_GLNIFLOKBPM: 0, - }, - }, - // 应该是玩家成员列表 - Unk3300_CDCMBOKBLAK: []*proto.Unk3300_ADHENCIFKNI{ - { - ControllerId: 1, - }, - { - ControllerId: 2, - }, - }, - // BusinessType: 0, - // IntentionList: nil, - ChallengeList: []*proto.GCGDuelChallenge{ - { - ChallengeId: 906, - TotalProgress: 1, - }, - { - ChallengeId: 907, - TotalProgress: 1, - }, - { - ChallengeId: 903, - TotalProgress: 1, - }, - { - ChallengeId: 904, - TotalProgress: 1, - }, - { - ChallengeId: 905, - TotalProgress: 1, - }, - { - ChallengeId: 908, - TotalProgress: 1, - }, - { - ChallengeId: 909, - TotalProgress: 1, - }, - }, - Round: 1, - ControllerId: 1, - HistoryMsgPackList: []*proto.GCGMessagePack{ - { - MsgList: []*proto.GCGMessage{ - { - Message: &proto.GCGMessage_PhaseChange{PhaseChange: &proto.GCGMsgPhaseChange{ - BeforePhase: proto.GCGPhaseType_GCG_PHASE_TYPE_START, - AllowControllerMap: []*proto.Uint32Pair{ - { - Key: 1, - Value: 1, - }, - { - Key: 2, - Value: 1, - }, - }, - }}, - }, + { + ChallengeId: 1, + CurProgress: 909, + TotalProgress: 0, }, }, - { - MsgList: []*proto.GCGMessage{ - { - Message: &proto.GCGMessage_UpdateController{UpdateController: &proto.GCGMsgUpdateController{ - AllowControllerMap: []*proto.Uint32Pair{ - { - Key: 1, - Value: 1, - }, - { - Key: 2, - }, - }, - }}, - }, - }, - }, - { - ActionType: proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, - MsgList: []*proto.GCGMessage{ - { - Message: &proto.GCGMessage_PhaseContinue{}, - }, - }, - }, - }, - // Unk3300_JHDDNKFPINA: 0, - CardIdList: []uint32{1103, 1301, 3001, 3302, 1301011}, - // Unk3300_JBBMBKGOONO: 0, - Phase: &proto.GCGPhase{ - PhaseType: proto.GCGPhaseType_GCG_PHASE_TYPE_START, - AllowControllerMap: map[uint32]uint32{ - 1: 1, - 2: 0, + // TODO 创建完卡牌都记录到历史卡牌内 + HistoryCardList: nil, + Round: game.roundInfo.roundNum, + ControllerId: gameController.controllerId, + HistoryMsgPackList: game.historyMsgPackList, + Unk3300_JHDDNKFPINA: 0, + // CardIdList 游戏内的所有卡牌Id + CardIdList: make([]uint32, 0, 0), + Unk3300_JBBMBKGOONO: 0, // Unk + // 阶段数据 + Phase: &proto.GCGPhase{ + PhaseType: game.roundInfo.phaseType, + AllowControllerMap: game.roundInfo.allowControllerMap, }, }, } - gcgAskDuelRsp.Duel.HistoryCardList = gcgAskDuelRsp.Duel.CardList - + for _, controller := range game.controllerMap { + // 玩家信息列表 + gcgControllerShowInfo := &proto.GCGControllerShowInfo{ + ControllerId: controller.controllerId, + ProfilePicture: &proto.ProfilePicture{}, + } + // 如果为玩家则更改为玩家信息 + if controller.controllerType == ControllerType_Player { + gcgControllerShowInfo.ProfilePicture.AvatarId = player.HeadImage + gcgControllerShowInfo.ProfilePicture.AvatarId = player.AvatarMap[player.HeadImage].Costume + } + gcgAskDuelRsp.Duel.ShowInfoList = append(gcgAskDuelRsp.Duel.ShowInfoList) + // FieldList 玩家牌盒信息 卡牌显示相关 + playerField := &proto.GCGPlayerField{ + Unk3300_IKJMGAHCFPM: 0, + // 卡牌图片 + ModifyZoneMap: make(map[uint32]*proto.GCGZone, len(controller.cardMap)), + Unk3300_GGHKFFADEAL: 0, + Unk3300_AOPJIOHMPOF: &proto.GCGZone{ + CardList: []uint32{}, + }, + Unk3300_FDFPHNDOJML: 0, + // 卡牌技能? + Unk3300_IPLMHKCNDLE: &proto.GCGZone{ + CardList: []uint32{}, // 官服CardList: []uint32{5}, + }, + Unk3300_EIHOMDLENMK: &proto.GCGZone{ + CardList: []uint32{}, + }, + WaitingList: []*proto.GCGWaitingCharacter{}, + Unk3300_PBECINKKHND: 0, + ControllerId: controller.controllerId, + // 卡牌位置 + Unk3300_INDJNJJJNKL: &proto.GCGZone{ + CardList: make([]uint32, 0, len(controller.cardMap)), + }, + Unk3300_EFNAEFBECHD: &proto.GCGZone{ + CardList: []uint32{}, + }, + IsPassed: false, + IntentionList: []*proto.GCGPVEIntention{}, + DiceSideList: []proto.GCGDiceSideType{}, + DeckCardNum: 0, + Unk3300_GLNIFLOKBPM: 0, + } + // 卡牌信息 + for _, info := range controller.cardMap { + gcgCard := &proto.GCGCard{ + TagList: info.tagList, + Guid: info.guid, + IsShow: info.isShow, + TokenList: make([]*proto.GCGToken, 0, 0), + FaceType: info.faceType, + SkillIdList: info.skillIdList, + SkillLimitsList: make([]*proto.GCGSkillLimitsInfo, 0, 0), + Id: info.cardId, + ControllerId: controller.controllerId, + } + // Token + for k, v := range info.tokenMap { + gcgCard.TokenList = append(gcgCard.TokenList, &proto.GCGToken{ + Value: v, + Key: k, + }) + } + // TODO SkillLimitsList + for _, skillId := range info.skillLimitList { + gcgCard.SkillLimitsList = append(gcgCard.SkillLimitsList, &proto.GCGSkillLimitsInfo{ + SkillId: skillId, + LimitsList: nil, // TODO 技能限制列表 + }) + } + gcgAskDuelRsp.Duel.CardList = append(gcgAskDuelRsp.Duel.CardList, gcgCard) + gcgAskDuelRsp.Duel.CardIdList = append(gcgAskDuelRsp.Duel.CardIdList, info.cardId) + // Field + playerField.ModifyZoneMap[info.guid] = &proto.GCGZone{CardList: []uint32{}} + playerField.Unk3300_INDJNJJJNKL.CardList = append(playerField.Unk3300_INDJNJJJNKL.CardList, info.guid) + } + // 添加完所有卡牌的位置之类的信息 添加这个牌盒 + gcgAskDuelRsp.Duel.FieldList = append(gcgAskDuelRsp.Duel.FieldList, playerField) + // Unk3300_CDCMBOKBLAK + gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK = append(gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK, &proto.Unk3300_ADHENCIFKNI{ + BeginTime: 0, + TimeStamp: 0, + ControllerId: controller.controllerId, + }) + } GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp) } -// GCGInitFinishReq GCG决斗请求 +// GCGInitFinishReq GCG初始化完成请求 func (g *GameManager) GCGInitFinishReq(player *model.Player, payloadMsg pb.Message) { - GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, &proto.GCGInitFinishRsp{}) + // 获取玩家所在的游戏 + game, ok := GCG_MANAGER.gameMap[player.GCGCurGameGuid] + if !ok { + g.CommonRetError(cmd.GCGInitFinishRsp, player, &proto.GCGInitFinishRsp{}, proto.Retcode_RET_GCG_GAME_NOT_RUNNING) + return + } + // 获取玩家的操控者对象 + gameController := game.GetControllerByUserId(player.PlayerID) + if gameController == nil { + g.CommonRetError(cmd.GCGInitFinishRsp, player, &proto.GCGInitFinishRsp{}, proto.Retcode_RET_GCG_NOT_IN_GCG_DUNGEON) + return + } + + // 更改操控者加载状态 + gameController.loadState = ControllerLoadState_InitFinish + + GAME_MANAGER.SendMsg(cmd.GCGInitFinishRsp, player.PlayerID, player.ClientSeq, &proto.GCGInitFinishRsp{}) + + // 检查所有玩家是否已加载完毕 + game.CheckAllInitFinish() +} + +// SendGCGMessagePackNotify 发送GCG消息包通知 +func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, serverSeq uint32, msgPackList []*proto.GCGMessagePack) { + // 确保为玩家 + if controller.player == nil { + return + } + // 确保加载完成 + if controller.loadState != ControllerLoadState_InitFinish { + return + } + // PacketGCGMessagePackNotify + gcgMessagePackNotify := &proto.GCGMessagePackNotify{ + ServerSeq: serverSeq, + MsgPackList: msgPackList, + } + GAME_MANAGER.SendMsg(cmd.GCGMessagePackNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgMessagePackNotify) } // PacketGCGGameBriefDataNotify GCG游戏简要数据通知 -func (g *GameManager) PacketGCGGameBriefDataNotify(player *model.Player, businessType proto.GCGGameBusinessType, gameId uint32) *proto.GCGGameBriefDataNotify { +func (g *GameManager) PacketGCGGameBriefDataNotify(player *model.Player, businessType proto.GCGGameBusinessType, game *GCGGame) *proto.GCGGameBriefDataNotify { gcgGameBriefDataNotify := &proto.GCGGameBriefDataNotify{ GcgBriefData: &proto.GCGGameBriefData{ - BusinessType: businessType, - PlatformType: uint32(proto.PlatformType_PLATFORM_TYPE_PC), // TODO 根据玩家设备修改 - GameId: gameId, - PlayerBriefList: []*proto.GCGPlayerBriefData{ - { - Uid: player.PlayerID, - ControllerId: 1, - ProfilePicture: &proto.ProfilePicture{ - AvatarId: player.TeamConfig.GetActiveAvatarId(), - CostumeId: player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Costume, - }, - NickName: player.NickName, - CardIdList: []uint32{1301, 1103}, - }, - { - ControllerId: 2, - ProfilePicture: &proto.ProfilePicture{}, - CardIdList: []uint32{3001, 3302}, - }, - }, + BusinessType: businessType, + PlatformType: uint32(proto.PlatformType_PLATFORM_TYPE_PC), // TODO 根据玩家设备修改 + GameId: game.gameId, + PlayerBriefList: make([]*proto.GCGPlayerBriefData, 0, len(game.controllerMap)), }, - IsNewGame: true, + IsNewGame: true, // 根据游戏修改 + } + for _, controller := range game.controllerMap { + gcgPlayerBriefData := &proto.GCGPlayerBriefData{ + ControllerId: controller.controllerId, + ProfilePicture: new(proto.ProfilePicture), + CardIdList: make([]uint32, 0, len(controller.cardMap)), + } + // 玩家信息 + if controller.player != nil { + gcgPlayerBriefData.Uid = player.PlayerID + gcgPlayerBriefData.ProfilePicture.AvatarId = player.TeamConfig.GetActiveAvatarId() + gcgPlayerBriefData.ProfilePicture.CostumeId = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Costume + gcgPlayerBriefData.NickName = player.NickName + } + gcgGameBriefDataNotify.GcgBriefData.PlayerBriefList = append(gcgGameBriefDataNotify.GcgBriefData.PlayerBriefList) } return gcgGameBriefDataNotify } diff --git a/gs/model/player.go b/gs/model/player.go index d4f32591..7835440f 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -89,7 +89,7 @@ func (p *Player) InitAll() { p.StaminaInfo = new(StaminaInfo) p.VehicleInfo = new(VehicleInfo) p.VehicleInfo.LastCreateEntityIdMap = make(map[uint32]uint32) - p.GCGInfo = NewGCGInfo() + p.GCGInfo = NewGCGInfo() // 临时测试用数据 p.InitAllAvatar() p.InitAllWeapon() p.InitAllItem() diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index 6220101a..f2884d30 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -264,6 +264,7 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(GCGAskDuelRsp, &proto.GCGAskDuelRsp{}) // GCG决斗响应 c.registerMessage(GCGInitFinishReq, &proto.GCGInitFinishReq{}) // GCG初始化完成请求 c.registerMessage(GCGInitFinishRsp, &proto.GCGInitFinishRsp{}) // GCG初始化完成响应 + c.registerMessage(GCGMessagePackNotify, &proto.GCGMessagePackNotify{}) // GCG消息包通知 // // TODO 客户端开始GCG游戏 // c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求