package main import ( "math" "sort" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/srvlib" "mongo.games.com/game/common" "mongo.games.com/game/model" serverproto "mongo.games.com/game/protocol/server" webapi2 "mongo.games.com/game/protocol/webapi" "mongo.games.com/game/webapi" ) func init() { ClockMgrSington.RegisteSinker(SceneMgrSingleton) } var SceneMgrSingleton = &SceneMgr{ scenes: make(map[int]*Scene), privateAutoId: common.PrivateSceneStartId, matchAutoId: common.MatchSceneStartId, coinSceneAutoId: common.CoinSceneStartId, hundredSceneAutoId: common.HundredSceneStartId, } // SceneMgr 房间管理器 type SceneMgr struct { BaseClockSinker // 驱动时间事件 scenes map[int]*Scene // 房间id: Scene privateAutoId int // 私人房房间号 matchAutoId int // 比赛场房间号 coinSceneAutoId int // 金币场房间号 hundredSceneAutoId int // 百人场房间号 } // AllocReplayCode 获取回访码 func (m *SceneMgr) AllocReplayCode() string { code, _ := model.GetOneReplayId() return code } // GenOnePrivateSceneId 生产一个私人房间id func (m *SceneMgr) GenOnePrivateSceneId() int { m.privateAutoId++ if m.privateAutoId > common.PrivateSceneMaxId { m.privateAutoId = common.PrivateSceneStartId } return m.privateAutoId } // GenOneCoinSceneId 生产一个金币场房间id func (m *SceneMgr) GenOneCoinSceneId() int { m.coinSceneAutoId++ if m.coinSceneAutoId > common.CoinSceneMaxId { m.coinSceneAutoId = common.CoinSceneStartId } return m.coinSceneAutoId } // GenOneHundredSceneId 生产一个百人场房间id func (m *SceneMgr) GenOneHundredSceneId() int { m.hundredSceneAutoId++ if m.hundredSceneAutoId > common.HundredSceneMaxId { m.hundredSceneAutoId = common.HundredSceneStartId } return m.hundredSceneAutoId } // GenOneMatchSceneId 生产一个比赛场房间id func (m *SceneMgr) GenOneMatchSceneId() int { m.matchAutoId++ if m.matchAutoId > common.MatchSceneMaxId { m.matchAutoId = common.MatchSceneStartId } return m.matchAutoId } // GetScene 获取房间对象 func (m *SceneMgr) GetScene(sceneId int) *Scene { if s, exist := m.scenes[sceneId]; exist && !s.deleting { return s } return nil } // GetScenesByGame 根据游戏id查询房间 func (m *SceneMgr) GetScenesByGame(gameId int) []*Scene { var scenes []*Scene for _, value := range m.scenes { if value.gameId == gameId { s := m.GetScene(value.sceneId) if s != nil { scenes = append(scenes, value) } } } return scenes } // GetScenesByGameFreeId 根据场次id查询房间 func (m *SceneMgr) GetScenesByGameFreeId(gameFreeId int32) []*Scene { var scenes []*Scene for _, value := range m.scenes { if value.dbGameFree.GetId() == gameFreeId { s := m.GetScene(value.sceneId) if s != nil { scenes = append(scenes, value) } } } return scenes } // MarshalAllRoom 获取房间列表 func (m *SceneMgr) MarshalAllRoom(platform string, groupId, gameId int, gameMode, clubId, sceneMode, sceneId int, gameFreeId, snId int32, start, end, pageSize int32) ([]*webapi2.RoomInfo, int32, int32) { roomInfo := make([]*webapi2.RoomInfo, 0, len(m.scenes)) var isNeedFindAll = false if model.GameParamData.IsFindRoomByGroup && platform != "" && snId != 0 && gameId == 0 && gameMode == 0 && sceneId == -1 && groupId == 0 && clubId == 0 && sceneMode == 0 { p := PlayerMgrSington.GetPlayerBySnId(snId) if p != nil && p.Platform == platform { isNeedFindAll = true } } for _, s := range m.scenes { if (((s.limitPlatform != nil && s.limitPlatform.IdStr == platform) || platform == "") && ((s.gameId == gameId && s.gameMode == gameMode) || gameId == 0) && (s.sceneId == sceneId || sceneId == 0) && (s.groupId == int32(groupId) || groupId == 0) && (s.ClubId == int32(clubId) || clubId == 0) && (s.dbGameFree.GetId() == gameFreeId || gameFreeId == 0) && (s.sceneMode == sceneMode || sceneMode == -1)) || isNeedFindAll { var platformName string if s.limitPlatform != nil { platformName = s.limitPlatform.IdStr } si := &webapi2.RoomInfo{ Platform: platformName, SceneId: int32(s.sceneId), GameId: int32(s.gameId), GameMode: int32(s.gameMode), SceneMode: int32(s.sceneMode), GroupId: s.groupId, Creator: s.creator, Agentor: s.agentor, ReplayCode: s.replayCode, Params: common.CopySliceInt64ToInt32(s.params), PlayerCnt: int32(len(s.players) - s.robotNum), RobotCnt: int32(s.robotNum), CreateTime: s.createTime.Unix(), BaseScore: s.dbGameFree.BaseScore, } if common.IsLocalGame(s.gameId) { si.BaseScore = s.BaseScore } if s.paramsEx != nil && len(s.paramsEx) > 0 { si.GameFreeId = s.paramsEx[0] } if s.starting { si.Start = 1 } else { si.Start = 0 } if s.IsHundredScene() { si.Start = 1 } if s.gameSess != nil { si.SrvId = s.gameSess.GetSrvId() } cnt := 0 total := len(s.players) robots := []int32{} isContinue := false if snId != 0 { for _, p := range s.players { if p.SnId == int32(snId) { isContinue = true break } } } else { isContinue = true } if !isContinue { continue } //优先显示玩家 for id, p := range s.players { if !p.IsRob || total < 10 { si.PlayerIds = append(si.PlayerIds, id) cnt++ } else { robots = append(robots, id) } if cnt > 10 { break } } //不够再显示机器人 if total > cnt && cnt < 10 && len(robots) != 0 { for i := 0; cnt < 10 && i < len(robots); i++ { si.PlayerIds = append(si.PlayerIds, robots[i]) cnt++ if cnt > 10 { break } } } roomInfo = append(roomInfo, si) } } sort.Slice(roomInfo, func(i, j int) bool { if roomInfo[i].CreateTime < roomInfo[j].CreateTime || (roomInfo[i].CreateTime == roomInfo[j].CreateTime && roomInfo[i].SceneId < roomInfo[j].SceneId) { return true } return false }) //分页处理 roomSum := float64(len(roomInfo)) //房间总数 pageCount := int32(math.Ceil(roomSum / float64(pageSize))) //总页数 if roomSum <= float64(start) { start = 0 } if roomSum < float64(end) { end = int32(roomSum) } needList := roomInfo[start:end] //需要的房间列表 if len(needList) > 0 { return needList, pageCount, int32(roomSum) } return nil, 0, int32(roomSum) } // CreateScene 创建房间 func (m *SceneMgr) CreateScene(agentor, creator int32, sceneId, gameId, gameMode, sceneMode int, clycleTimes int32, numOfGames int32, params []int64, gs *GameSession, limitPlatform *Platform, groupId int32, dbGameFree *serverproto.DB_GameFree, paramsEx ...int32) *Scene { logger.Logger.Trace("(this *SceneMgr) CreateScene ") s := NewScene(agentor, creator, sceneId, gameId, gameMode, sceneMode, clycleTimes, numOfGames, params, gs, limitPlatform, groupId, dbGameFree, paramsEx...) if s == nil { return nil } m.scenes[sceneId] = s if !s.IsMatchScene() && dbGameFree != nil && limitPlatform != nil { //平台水池设置 gs.DetectCoinPoolSetting(limitPlatform.IdStr, dbGameFree.GetId(), s.groupId) } gs.AddScene(s) var platformName string if limitPlatform != nil { platformName = limitPlatform.IdStr } logger.Logger.Infof("(this *SceneMgr) CreateScene (gameId=%v, mode=%v), SceneId=%v groupid=%v platform=%v", gameId, gameMode, sceneId, groupId, platformName) return s } // CreateLocalGameScene 创建本地游戏房间 func (m *SceneMgr) CreateLocalGameScene(creator int32, sceneId, gameId, gameSite, sceneMode int, clycleTimes int32, params []int64, gs *GameSession, limitPlatform *Platform, playerNum int, dbGameFree *serverproto.DB_GameFree, baseScore, groupId int32, paramsEx ...int32) *Scene { logger.Logger.Trace("(this *SceneMgr) CreateLocalGameScene gameSite: ", gameSite, " sceneMode: ", sceneMode) s := NewLocalGameScene(creator, sceneId, gameId, gameSite, sceneMode, clycleTimes, params, gs, limitPlatform, playerNum, dbGameFree, baseScore, groupId, paramsEx...) if s == nil { return nil } m.scenes[sceneId] = s gs.AddScene(s) var platformName string if limitPlatform != nil { platformName = limitPlatform.IdStr } logger.Logger.Infof("(this *SceneMgr) CreateScene (gameId=%v), SceneId=%v platform=%v", gameId, sceneId, platformName) return s } // DestroyScene 解散房间 // 房间销毁,游戏服务断开 func (m *SceneMgr) DestroyScene(sceneId int, isCompleted bool) { logger.Logger.Trace("(this *SceneMgr) DestroyScene ") s, ok := m.scenes[sceneId] if !ok || s == nil { return } switch { case s.IsCoinScene(): CoinSceneMgrSingleton.OnDestroyScene(s.sceneId) case s.IsHundredScene(): HundredSceneMgrSington.OnDestroyScene(s.sceneId) case s.IsMatchScene(): MatchSceneMgrSingleton.OnDestroyScene(s.sceneId) } s.gameSess.DelScene(s) s.OnClose() delete(m.scenes, s.sceneId) logger.Logger.Infof("(this *SceneMgr) DestroyScene, SceneId=%v", sceneId) } func (m *SceneMgr) OnPlayerLeaveScene(s *Scene, p *Player) { logger.Logger.Trace("(this *SceneMgr) OnPlayerLeaveScene", p.SnId) // 记录玩家在每个游戏场次最后进入的房间号 // 只记录金币场 if s.IsCoinScene() { const MINHOLD = 10 const MAXHOLD = 20 holdCnt := MINHOLD if s.csp != nil { holdCnt = s.csp.GetHasTruePlayerSceneCnt() + 2 if holdCnt < MINHOLD { holdCnt = MINHOLD } if holdCnt > MAXHOLD { holdCnt = MAXHOLD } } if p.lastSceneId == nil { p.lastSceneId = make(map[int32][]int32) } id := s.dbGameFree.GetId() if sceneIds, exist := p.lastSceneId[id]; exist { if !common.InSliceInt32(sceneIds, int32(s.sceneId)) { sceneIds = append(sceneIds, int32(s.sceneId)) cnt := len(sceneIds) if cnt > holdCnt { sceneIds = sceneIds[cnt-holdCnt:] } p.lastSceneId[id] = sceneIds } } else { p.lastSceneId[id] = []int32{int32(s.sceneId)} } } } func (m *SceneMgr) DoDelete(sceneId []int, isGrace bool) { if len(sceneId) == 0 { return } var ids []int64 for _, v := range sceneId { ids = append(ids, int64(v)) s, ok := m.scenes[v] if !isGrace && ok && s != nil { s.deleting = true s.force = true } } pack := &serverproto.WGDestroyScene{ Ids: ids, IsGrace: isGrace, } srvlib.ServerSessionMgrSington.Broadcast(int(serverproto.SSPacketID_PACKET_WG_DESTROYSCENE), pack, common.GetSelfAreaId(), srvlib.GameServerType) } // GetThirdScene 获取三方游戏房间 //func (m *SceneMgr) GetThirdScene(i webapi.IThirdPlatform) *Scene { // if i == nil { // return nil // } // sceneId := i.GetPlatformBase().SceneId // scene := m.scenes[sceneId] // if scene != nil { // return scene // } // // gs := GameSessMgrSington.GetMinLoadSess(i.GetPlatformBase().BaseGameID) // if gs != nil { // limitPlatform := PlatformMgrSingleton.GetPlatform(DefaultPlatform) // var gameMode = common.SceneMode_Thr // dbGameFree := srvdata.PBDB_GameFreeMgr.GetData(i.GetPlatformBase().VultGameID) // scene := SceneMgrSingleton.CreateScene(0, 0, sceneId, i.GetPlatformBase().BaseGameID, gameMode, int(common.SceneMode_Thr), 1, -1, // []int64{}, gs, limitPlatform, 0, dbGameFree, i.GetPlatformBase().VultGameID) // return scene // } else { // logger.Logger.Errorf("Get %v game min session failed.", i.GetPlatformBase().BaseGameID) // return nil // } //} //=========================ClockSinker=============================== // InterestClockEvent 接收所有时间事件 func (m *SceneMgr) InterestClockEvent() int { return 1 << CLOCK_EVENT_MINUTE } func (m *SceneMgr) OnMiniTimer() { // 解散空闲房间 for _, s := range m.scenes { if webapi.ThridPlatformMgrSington.FindPlatformByPlatformBaseGameId(s.gameId) != nil { continue } switch { case s.IsCoinScene(): if s.IsLongTimeInactive() { if s.dbGameFree.GetCreateRoomNum() == 0 { logger.Logger.Warnf("SceneMgr.DeleteLongTimeInactive CoinScene DoDelete scene:%v IsLongTimeInactive", s.sceneId) s.DoDelete(false) } if s.dbGameFree.GetCreateRoomNum() > 0 && s.csp != nil && s.csp.GetRoomNum() > int(s.dbGameFree.GetCreateRoomNum()) { logger.Logger.Warnf("SceneMgr.DeleteLongTimeInactive CoinScene DoDelete scene:%v IsLongTimeInactive", s.sceneId) s.DoDelete(false) } } case s.IsPrivateScene(): if s.IsLongTimeInactive() { logger.Logger.Warnf("SceneMgr.DeleteLongTimeInactive PrivateScene DoDelete scene:%v IsLongTimeInactive", s.sceneId) s.DoDelete(false) } } } }