package main import ( "mongo.games.com/game/common" "mongo.games.com/goserver/core/logger" "mongo.games.com/game/model" gamehallproto "mongo.games.com/game/protocol/gamehall" serverproto "mongo.games.com/game/protocol/server" "mongo.games.com/game/srvdata" ) // CoinScenePool 房间池 type CoinScenePool struct { platform string // 平台id groupId int32 // 组id id int32 // 场次id dbGameFree *serverproto.DB_GameFree // 场次配置 dbGameRule *serverproto.DB_GameRule // 场次配置 scenes map[int]*Scene // 所有房间,房间id players map[int32]struct{} // 玩家id // 扩展数据 extraData interface{} // 房间池规则 policy ICoinScenePool } func newCoinScenePool(platform string, groupId int32, dbGameFree *serverproto.DB_GameFree) *CoinScenePool { if dbGameFree == nil { return nil } if platform == "" { platform = DefaultPlatform } dbGameRule := srvdata.PBDB_GameRuleMgr.GetData(dbGameFree.GetGameRule()) if dbGameRule == nil { logger.Logger.Errorf("Coin scene pool init failed,%v game rule data not find.", dbGameFree.GetGameRule()) return nil } csp := &CoinScenePool{ platform: platform, groupId: groupId, id: dbGameFree.GetId(), dbGameFree: dbGameFree, dbGameRule: dbGameRule, scenes: make(map[int]*Scene), players: make(map[int32]struct{}), policy: new(BaseCoinScenePool), // 默认方式 } policy := GetCoinScenePool(dbGameFree.GetGameId()) if policy != nil { csp.policy = policy csp.extraData = policy.New() } return csp } func (csp *CoinScenePool) GetPlayerNum() int32 { return int32(len(csp.players)) } func (csp *CoinScenePool) GetFakePlayerNum() int32 { //if csp.dbGameFree != nil { // correctNum := csp.dbGameFree.GetCorrectNum() // correctRate := csp.dbGameFree.GetCorrectRate() // count := csp.GetPlayerNum() // return correctNum + count*correctRate/100 + csp.numDeviation //} return 0 } // GetSceneType 获取场次id func (csp *CoinScenePool) GetSceneType() int { if csp.dbGameFree != nil { return int(csp.dbGameFree.GetSceneType()) } return 0 } // CanInviteRob 能否邀请机器人 func (csp *CoinScenePool) CanInviteRob() bool { if csp.dbGameFree != nil { return csp.dbGameFree.GetBot() != 0 } return false } // CanEnter 检查入场条件 func (csp *CoinScenePool) CanEnter(p *Player) gamehallproto.OpResultCode { if csp.dbGameFree == nil || p == nil { return gamehallproto.OpResultCode_OPRC_Error } //检测房间状态是否开启 gps := PlatformMgrSingleton.GetGameFree(p.Platform, csp.id) if gps == nil || !gps.Status { return gamehallproto.OpResultCode_OPRC_RoomHadClosed } dbGameFree := csp.dbGameFree if dbGameFree == nil { return gamehallproto.OpResultCode_OPRC_RoomHadClosed } //检查游戏次数限制 if !p.IsRob { todayData, _ := p.GetDaliyGameData(int(dbGameFree.GetId())) if dbGameFree.GetPlayNumLimit() != 0 && todayData != nil && todayData.GameTimes >= int64(dbGameFree.GetPlayNumLimit()) { return gamehallproto.OpResultCode_OPRC_RoomGameTimes } } return csp.policy.CanEnter(csp, p) } // CanAudienceEnter 检查观众入场条件 func (csp *CoinScenePool) CanAudienceEnter(p *Player) gamehallproto.OpResultCode { if csp.dbGameFree == nil || p == nil { return gamehallproto.OpResultCode_OPRC_Error } //检测房间状态是否开启 gps := PlatformMgrSingleton.GetGameFree(p.Platform, csp.id) if gps == nil { return gamehallproto.OpResultCode_OPRC_RoomHadClosed } dbGameFree := csp.dbGameFree if dbGameFree == nil { return gamehallproto.OpResultCode_OPRC_RoomHadClosed } return csp.policy.CanAudienceEnter(csp, p) } // AddScene 添加房间 func (csp *CoinScenePool) AddScene(s *Scene) { if s == nil { return } csp.scenes[s.sceneId] = s s.csp = csp if csp.groupId != 0 { CoinSceneMgrSingleton.groupOfScene[s.sceneId] = csp.groupId } else { CoinSceneMgrSingleton.platformOfScene[s.sceneId] = csp.platform } } // PlayerEnter 玩家进入房间池 // exclude 排除的房间id // isChangeRoom 是否换房 func (csp *CoinScenePool) PlayerEnter(p *Player, roomId int32, exclude []int32, isChangeRoom bool) gamehallproto.OpResultCode { if ret := csp.CanEnter(p); ret != gamehallproto.OpResultCode_OPRC_Sucess { logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter find snid:%v csp.CanEnter coin:%v ret:%v id:%v", p.SnId, p.Coin, ret, csp.dbGameFree.GetId()) return ret } if p.scene != nil { logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter[p.scene != nil] find snid:%v in scene:%v gameId:%v", p.SnId, p.scene.sceneId, p.scene.gameId) return gamehallproto.OpResultCode_OPRC_Error } var scene *Scene // 进入房间 // 指定房间id进入,忽略排除exclude,只有机器人和进入预创建房间才允许 if roomId != 0 && (p.IsRob || csp.dbGameFree.GetCreateRoomNum() != 0) { if s, ok := csp.scenes[int(roomId)]; ok { if s != nil && !s.deleting { //指定房间id进入,那么忽略掉排除id if s.IsFull() { return gamehallproto.OpResultCode_OPRC_RoomIsFull } if sp, ok := s.sp.(*ScenePolicyData); ok { if !s.starting || sp.EnterAfterStart { scene = s } else { logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter[!s.starting || sp.EnterAfterStart] snid:%v sceneid:%v starting:%v EnterAfterStart:%v", p.SnId, s.sceneId, s.starting, sp.EnterAfterStart) return gamehallproto.OpResultCode_OPRC_Error } } } } else { logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter(robot:%v,roomid:%v, exclude:%v, isChangeRoom:%v) no found scene", p.SnId, roomId, exclude, isChangeRoom) return gamehallproto.OpResultCode_OPRC_Error } } if scene == nil { var ret gamehallproto.OpResultCode ret, scene = csp.policy.PlayerEnter(csp, p, exclude, isChangeRoom) if ret != gamehallproto.OpResultCode_OPRC_Sucess { return ret } } // 没有找到房间,创建新房间 if scene == nil { scene = csp.policy.NewScene(csp, p) if scene != nil { csp.AddScene(scene) } else { logger.Logger.Errorf("Create %v scene failed.", csp.id) } } if scene != nil { if scene.PlayerEnter(p, -1, isChangeRoom) { csp.OnPlayerEnter(p, scene) return gamehallproto.OpResultCode_OPRC_Sucess } } logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter snid:%v not found scene", p.SnId) return gamehallproto.OpResultCode_OPRC_SceneServerMaintain } // AudienceEnter 观众入场 func (csp *CoinScenePool) AudienceEnter(p *Player, roomId int32, exclude []int32, isChangeRoom bool) gamehallproto.OpResultCode { if ret := csp.CanAudienceEnter(p); ret != gamehallproto.OpResultCode_OPRC_Sucess { logger.Logger.Warnf("(csp *CoinScenePool) AudienceEnter find snid:%v csp.CanEnter coin:%v ret:%v id:%v", p.SnId, p.Coin, ret, csp.dbGameFree.GetId()) return ret } if p.scene != nil { logger.Logger.Warnf("(csp *CoinScenePool) AudienceEnter[p.scene != nil] find snid:%v in scene:%v gameId:%v", p.SnId, p.scene.sceneId, p.scene.gameId) return gamehallproto.OpResultCode_OPRC_Error } var scene *Scene if roomId != 0 { if s, ok := csp.scenes[int(roomId)]; ok { if s != nil && !s.deleting { scene = s } else { logger.Logger.Warnf("(csp *CoinScenePool) AudienceEnter[!s.starting || sp.EnterAfterStart] snid:%v sceneid:%v starting:%v EnterAfterStart:%v", p.SnId, s.sceneId, s.starting) } } } if scene == nil { var ret gamehallproto.OpResultCode ret, scene = csp.policy.AudienceEnter(csp, p, exclude, isChangeRoom) if ret != gamehallproto.OpResultCode_OPRC_Sucess { return ret } } if scene == nil { return gamehallproto.OpResultCode_OPRC_NoFindDownTiceRoom } // 预创建房间检查观众数量 if scene.IsPreCreateScene() && scene.GetAudienceCnt() >= model.GameParamData.MaxAudienceNum { return gamehallproto.OpResultCode_OPRC_RoomIsFull } if scene.AudienceEnter(p, isChangeRoom) { csp.OnPlayerEnter(p, scene) return gamehallproto.OpResultCode_OPRC_Sucess } logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter snid:%v not found scene", p.SnId) return gamehallproto.OpResultCode_OPRC_NoFindDownTiceRoom } // OnPlayerEnter 玩家进入房间完成 func (csp *CoinScenePool) OnPlayerEnter(p *Player, scene *Scene) { csp.players[p.SnId] = struct{}{} csp.policy.OnPlayerEnter(csp, p, scene) } // PlayerLeave 玩家离开房间 func (csp *CoinScenePool) PlayerLeave(p *Player, reason int) bool { if p.scene == nil { return true } if p.scene.csp != csp && p.scene == csp.scenes[p.scene.sceneId] { logger.Logger.Error("bug") } if p.scene.csp != csp { return false } if p.scene != csp.scenes[p.scene.sceneId] { logger.Logger.Error("bug") } s, ok := csp.scenes[p.scene.sceneId] if !ok || s == nil { return false } if !s.HasPlayer(p) { return false } if !csp.policy.PlayerLeave(csp, p, reason) { return false } s.PlayerLeave(p, reason) logger.Logger.Tracef("(csp *CoinScenePool) PlayerLeave snid:%v in scene:%v", p.SnId, s.sceneId) csp.policy.OnPlayerLeave(csp, s, p) csp.OnPlayerLeave(s, p) return true } // AudienceLeave 观众离开房间 func (csp *CoinScenePool) AudienceLeave(p *Player, reason int) bool { if p.scene == nil { return true } if p.scene.csp != csp { return false } s, ok := csp.scenes[p.scene.sceneId] if !ok || s == nil { return false } if !s.HasAudience(p) { return false } if !csp.policy.AudienceLeave(csp, p, reason) { return false } s.AudienceLeave(p, reason) logger.Logger.Tracef("(csp *CoinScenePool) AudienceLeave snid:%v in scene:%v", p.SnId, s.sceneId) csp.policy.OnPlayerLeave(csp, s, p) csp.OnPlayerLeave(s, p) return true } // OnPlayerLeave 离开房间完成 func (csp *CoinScenePool) OnPlayerLeave(s *Scene, p *Player) { if s == nil || p == nil { return } delete(csp.players, p.SnId) // 玩家离开结算空房间的私人房 if s.IsPrivateScene() { if s.IsEmpty() { s.DoDelete(false) } return } // 解散空房间并且房间数量大于预创建房间数量 if s.IsPreCreateScene() { if s.IsEmpty() { var hasCnt int for _, scene := range csp.scenes { if s.limitPlatform.IdStr == scene.limitPlatform.IdStr { hasCnt++ } } if hasCnt > int(csp.dbGameFree.GetCreateRoomNum()) { s.DoDelete(false) } } } } // OnDestroyScene 解散房间 // 房间解散一定是游戏服确认的,worldsrv收到游戏房间解散消息后解散房间 func (csp *CoinScenePool) OnDestroyScene(sceneId int) { scene, ok := csp.scenes[sceneId] if !ok { return } logger.Logger.Tracef("(csp *CoinScenePool) OnDestroyScene scene:%v", sceneId) // todo 是否需要优化 for id := range scene.players { player := PlayerMgrSington.GetPlayerBySnId(id) if player != nil { if !player.IsRob { ctx := scene.GetPlayerGameCtx(player.SnId) if ctx != nil { //发送一个探针,等待ack后同步金币 player.TryRetrieveLostGameCoin(sceneId) } } } } for id := range scene.audiences { player := PlayerMgrSington.GetPlayerBySnId(id) if player != nil { if !player.IsRob { ctx := scene.GetPlayerGameCtx(player.SnId) if ctx != nil { //发送一个探针,等待ack后同步金币 player.TryRetrieveLostGameCoin(sceneId) } } } } csp.policy.OnDestroyScene(csp, sceneId) scene.csp = nil // 解除关联 delete(csp.scenes, sceneId) CoinSceneMgrSingleton.TouchCreateRoom(csp.platform, csp.dbGameFree.Id) } // PreCreateRoom 预创建房间 func (csp *CoinScenePool) PreCreateRoom() { if csp.platform == DefaultPlatform { return } if p := PlatformMgrSingleton.GetPlatform(csp.platform); p == nil || p.Disable { return } preCreateNum := int(csp.dbGameFree.GetCreateRoomNum()) if preCreateNum <= 0 || model.GameParamData.ClosePreCreateRoom { return } num := preCreateNum - csp.GetRoomNum(common.SceneMode_Public) if num > 0 { logger.Logger.Tracef("预创建房间 [inc:%v] platform:%v gameFreeId:%v", num, csp.platform, csp.dbGameFree.Id) for i := 0; i < num; i++ { scene := csp.policy.NewPreCreateScene(csp) if scene != nil { csp.AddScene(scene) } } } } func (csp *CoinScenePool) GetRoomNum(mode ...int) int { tp := 0 if len(mode) > 0 { tp = mode[0] } var num int for _, scene := range csp.scenes { if tp > 0 { if scene.IsSceneMode(tp) { num++ } } else { num++ } } return num } // ListRoom 房间列表 //func (csp *CoinScenePool) ListRoom(p *Player) bool { // if p.scene != nil { // logger.Logger.Warnf("(csp *CoinScenePool) PlayerListRoom[p.scene != nil] find snid:%v in scene:%v gameId:%v", p.SnId, p.scene.sceneId, p.scene.gameId) // return false // } // // if len(csp.scenes) == 0 { // return false // } // // pack := &gamehallproto.SCCoinSceneListRoom{ // Id: csp.dbGameFree.Id, // LimitCoin: csp.dbGameFree.LimitCoin, // MaxCoinLimit: csp.dbGameFree.MaxCoinLimit, // BaseScore: csp.dbGameFree.BaseScore, // MaxScore: csp.dbGameFree.MaxChip, // OtherIntParams: csp.dbGameFree.OtherIntParams, // } // // maxPlayerNum := 0 // for sceneId, s := range csp.scenes { // data := &gamehallproto.CoinSceneInfo{ // SceneId: proto.Int(sceneId), // PlayerNum: proto.Int(len(s.players)), // } // pack.Datas = append(pack.Datas, data) // maxPlayerNum = s.playerNum // } // pack.MaxPlayerNum = proto.Int(maxPlayerNum) // proto.SetDefaults(pack) // p.SendToClient(int(gamehallproto.CoinSceneGamePacketID_PACKET_SC_COINSCENE_LISTROOM), pack) // return true //} // GetHasTruePlayerSceneCnt 有真人的房间数量 func (csp *CoinScenePool) GetHasTruePlayerSceneCnt() int { cnt := 0 for _, s := range csp.scenes { if s.GetTruePlayerCnt() != 0 { cnt++ } } return cnt }