Files
hk4e/gs/game/gcg_manager.go
2023-01-05 23:44:55 +08:00

439 lines
13 KiB
Go

package game
import (
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/protocol/proto"
)
// ControllerType 操控者类型
type ControllerType uint8
const (
ControllerType_Player ControllerType = iota // 玩家
ControllerType_AI // AI
)
// GCGCardInfo 游戏对局内卡牌
type GCGCardInfo struct {
cardId uint32 // 卡牌Id
guid uint32 // 唯一Id
faceType uint32 // 卡面类型
tagList []uint32 // Tag
tokenMap map[uint32]uint32 // Token
skillIdList []uint32 // 技能Id列表
skillLimitList []uint32 // 技能限制列表
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 // 暂时不写
}
// GCGManager 七圣召唤管理器
type GCGManager struct {
gameMap map[uint32]*GCGGame // 游戏列表 uint32 -> guid
gameGuidCounter uint32 // 游戏guid生成计数器
}
func NewGCGManager() *GCGManager {
gcgManager := new(GCGManager)
gcgManager.gameMap = make(map[uint32]*GCGGame)
return gcgManager
}
// CreateGame 创建GCG游戏对局
func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGGame {
g.gameGuidCounter++
game := &GCGGame{
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
}
// 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: 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,
// }
// 记录操控者
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 生成操控者卡牌信息
// func (g *GCGManager) CreateGameCardInfo(controller *GCGController, gcgDeck *model.GCGDeck) *GCGCardInfo {
//
// }
// GetControllerByUserId 通过玩家Id获取GCGController对象
func (g *GCGGame) GetControllerByUserId(userId uint32) *GCGController {
for _, controller := range g.controllerMap {
// 为nil说明该操控者不是玩家
if controller.player == nil {
continue
}
if controller.player.PlayerID == userId {
return controller
}
}
return nil
}