package main import ( "mongo.games.com/goserver/core/logger" "mongo.games.com/game/model" "mongo.games.com/game/proto" gamehall_proto "mongo.games.com/game/protocol/gamehall" server_proto "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 *server_proto.DB_GameFree // 场次配置 dbGameRule *server_proto.DB_GameRule // 场次配置 scenes map[int]*Scene // 所有房间,房间id players map[int32]struct{} // 玩家id // 扩展数据 extraData interface{} // 匹配规则 policy ICoinScenePool } func NewCoinScenePool(platform string, groupId int32, dbGameFree *server_proto.DB_GameFree) *CoinScenePool { if dbGameFree == nil { return nil } 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) gamehall_proto.OpResultCode { if csp.dbGameFree == nil || p == nil { return gamehall_proto.OpResultCode_OPRC_Error } //检测房间状态是否开启 gps := PlatformMgrSingleton.GetGameFree(p.Platform, csp.id) if gps == nil || !gps.Status { return gamehall_proto.OpResultCode_OPRC_RoomHadClosed } dbGameFree := csp.dbGameFree if dbGameFree == nil { return gamehall_proto.OpResultCode_OPRC_RoomHadClosed } //检查游戏次数限制 if !p.IsRob { todayData, _ := p.GetDaliyGameData(int(dbGameFree.GetId())) if dbGameFree.GetPlayNumLimit() != 0 && todayData != nil && todayData.GameTimes >= int64(dbGameFree.GetPlayNumLimit()) { return gamehall_proto.OpResultCode_OPRC_RoomGameTimes } } return csp.policy.CanEnter(csp, p) } // CanAudienceEnter 检查观众入场条件 func (csp *CoinScenePool) CanAudienceEnter(p *Player) gamehall_proto.OpResultCode { if csp.dbGameFree == nil || p == nil { return gamehall_proto.OpResultCode_OPRC_Error } //检测房间状态是否开启 gps := PlatformMgrSingleton.GetGameFree(p.Platform, csp.id) if gps == nil { return gamehall_proto.OpResultCode_OPRC_RoomHadClosed } dbGameFree := csp.dbGameFree if dbGameFree == nil { return gamehall_proto.OpResultCode_OPRC_RoomHadClosed } return csp.policy.CanAudienceEnter(csp, p) } // PlayerEnter 玩家进入房间池 func (csp *CoinScenePool) PlayerEnter(p *Player, roomId int32, exclude []int32, ischangeroom bool) gamehall_proto.OpResultCode { if ret := csp.CanEnter(p); ret != gamehall_proto.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 gamehall_proto.OpResultCode_OPRC_Error } var scene *Scene // 进入房间 if roomId != 0 && (p.IsRob || p.GMLevel > 0 || csp.dbGameFree.GetCreateRoomNum() != 0) { if s, ok := csp.scenes[int(roomId)]; ok { if s != nil && !s.deleting { //指定房间id进入,那么忽略掉排除id if s.IsFull() { return gamehall_proto.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 gamehall_proto.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 gamehall_proto.OpResultCode_OPRC_Error } } if scene == nil { var ret gamehall_proto.OpResultCode ret, scene = csp.policy.PlayerEnter(csp, p, exclude, ischangeroom) if ret != gamehall_proto.OpResultCode_OPRC_Sucess { return ret } } if scene == nil { scene = csp.policy.NewScene(csp, p) if scene != nil { csp.scenes[scene.sceneId] = scene scene.csp = csp } else { logger.Logger.Errorf("Create %v scene failed.", csp.id) } } if scene != nil { if p.EnterScene(scene, ischangeroom, -1) { csp.OnPlayerEnter(p, scene) return gamehall_proto.OpResultCode_OPRC_Sucess } } logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter snid:%v not found scene", p.SnId) return gamehall_proto.OpResultCode_OPRC_SceneServerMaintain } // AudienceEnter 观众入场 func (csp *CoinScenePool) AudienceEnter(p *Player, roomId int32, exclude []int32, ischangeroom bool) gamehall_proto.OpResultCode { if ret := csp.CanAudienceEnter(p); ret != gamehall_proto.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 gamehall_proto.OpResultCode_OPRC_Error } var scene *Scene if roomId != 0 { if s, ok := csp.scenes[int(roomId)]; ok { if s != nil && !s.deleting /*&& s.sceneId != int(exclude)*/ { 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 gamehall_proto.OpResultCode ret, scene = csp.policy.AudienceEnter(csp, p, exclude, ischangeroom) if ret != gamehall_proto.OpResultCode_OPRC_Sucess { return ret } } if scene == nil { return gamehall_proto.OpResultCode_OPRC_NoFindDownTiceRoom } if scene != nil { // 预创建房间检查观众数量 if scene.IsPreCreateScene() && scene.GetAudienceCnt() >= model.GameParamData.MaxAudienceNum { return gamehall_proto.OpResultCode_OPRC_RoomIsFull } if scene.AudienceEnter(p, ischangeroom) { csp.OnPlayerEnter(p, scene) return gamehall_proto.OpResultCode_OPRC_Sucess } } logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter snid:%v not found scene", p.SnId) return gamehall_proto.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.ForceDelete(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.ForceDelete(false) } } } } // OnDestroyScene 解散房间 // todo 是否需要优化 func (csp *CoinScenePool) OnDestroyScene(sceneId int) { scene, ok := csp.scenes[sceneId] if !ok { return } 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) } // PreCreateRoom 预创建房间 func (csp *CoinScenePool) PreCreateRoom() { if csp.platform == DefaultPlatform { return } preCreateNum := int(csp.dbGameFree.GetCreateRoomNum()) if preCreateNum == 0 || model.GameParamData.ClosePreCreateRoom { return } if p := PlatformMgrSingleton.GetPlatform(csp.platform); p == nil || p.Disable { return } var num int for _, scene := range csp.scenes { if scene.limitPlatform.IdStr == csp.platform { num++ } } if num < preCreateNum { inc := preCreateNum - num for i := 0; i < inc; i++ { scene := csp.policy.NewPreCreateScene(csp) if scene != nil { csp.scenes[scene.sceneId] = scene scene.csp = csp } } } } // 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 } csp.PreCreateRoom() if len(csp.scenes) == 0 { return false } pack := &gamehall_proto.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 := &gamehall_proto.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(gamehall_proto.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 }