mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 15:42:25 +08:00
439 lines
13 KiB
Go
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
|
|
}
|