package main import ( "math/rand" "strconv" "time" rawproto "google.golang.org/protobuf/proto" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/srvlib" "mongo.games.com/goserver/srvlib/action" srvlibproto "mongo.games.com/goserver/srvlib/protocol" "mongo.games.com/game/common" "mongo.games.com/game/gamerule/tienlen" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/gamehall" hallproto "mongo.games.com/game/protocol/gamehall" serverproto "mongo.games.com/game/protocol/server" webapiproto "mongo.games.com/game/protocol/webapi" "mongo.games.com/game/srvdata" ) type PlayerGameCtx struct { takeCoin int64 //进房时携带的金币量 enterTs int64 //进入时间 } // Scene 场景(房间) type Scene struct { sceneId int // 场景id gameId int // 游戏id gameMode int // 废弃,游戏模式(玩法) sceneMode int // 房间模式,参考common.SceneMode_XXX params []int64 // 场景参数 playerNum int // 房间最大人数 robotNum int // 机器人数量 robotLimit int // 最大限制机器人数量 creator int32 // 创建者账号id replayCode string // 回放码 currRound int32 // 当前第几轮 totalRound int32 // 总共几轮,小于等于0表示无限轮 cycleTimes int32 // 循环次数,未使用 deleting bool // 正在删除 starting bool // 正在开始 closed bool // 房间已关闭 force bool // 强制删除 players map[int32]*Player // 玩家 audiences map[int32]*Player // 观众 seats [9]*Player // 座位 gameSess *GameSession // 所在gameserver sp ScenePolicy // 场景上的一些业务策略 createTime time.Time // 创建时间 lastTime time.Time // 最后活跃时间 startTime time.Time // 游戏开始时间 platform *Platform // 限制平台 groupId int32 // 组id dbGameFree *serverproto.DB_GameFree // 场次配置 gameCtx map[int32]*PlayerGameCtx // 进入房间的环境,没有机器人数据 SnId BaseScore int32 // 游戏底分,优先级,创建参数>本地配置>场次配置 SceneState int32 // 房间当前状态 Channel []string // 客户端类型 csp *CoinScenePool // 所在场景池 hp *HundredSceneMgr // 百人场房间池 // 以下为自定义字段 CloseCtrl bool // 调控开关 *serverproto.CustomParam // 房卡场参数 *serverproto.MatchParam // 比赛场参数 *webapiproto.RoomConfigSystem // 系统竞技馆房间 CustomWinSnId int32 // 房卡场胜利者 IsRecruit bool // 招募中 RecruitTimes int // 招募次数 } // NewScene 创建房间 func NewScene(args *CreateSceneParam) *Scene { gameId := int(args.GF.GetGameId()) gameMode := int(args.GF.GetGameMode()) sp := GetScenePolicy(gameId, gameMode) if sp == nil { logger.Logger.Errorf("NewScene sp == nil, gameId=%v gameMode=%v", gameId, gameMode) return nil } s := &Scene{ sceneId: args.RoomId, playerNum: int(args.PlayerNum), creator: args.CreateId, gameId: gameId, gameMode: gameMode, sceneMode: args.SceneMode, params: args.Params, cycleTimes: int32(args.CycleTimes), players: make(map[int32]*Player), audiences: make(map[int32]*Player), gameSess: args.GS, sp: sp, createTime: time.Now(), platform: args.Platform, groupId: 0, gameCtx: make(map[int32]*PlayerGameCtx), //进入房间的环境 dbGameFree: args.GF, currRound: 0, totalRound: int32(args.TotalRound), BaseScore: args.BaseScore, Channel: args.Channel, CustomParam: args.CustomParam, MatchParam: args.MatchParam, RoomConfigSystem: args.RoomConfigSystem, IsRecruit: args.IsRecruit, } // 最大房间人数 if s.playerNum <= 0 { s.playerNum = sp.GetPlayerNum() } // 底分 if s.BaseScore <= 0 { s.BaseScore = int32(sp.GetBaseScore()) } if s.BaseScore <= 0 { s.BaseScore = s.dbGameFree.GetBaseScore() } if s.cycleTimes <= 0 { s.cycleTimes = 1 } s.lastTime = s.createTime s.replayCode = SceneMgrSingleton.AllocReplayCode() if s.dbGameFree.GetMatchMode() == 0 { // 普通匹配设置最大机器人数量 number := s.dbGameFree.GetRobotNumRng() if len(number) >= 2 { if number[1] == number[0] { s.robotLimit = int(number[0]) } else { if number[1] < number[0] { number[1], number[0] = number[0], number[1] } s.robotLimit = int(number[1]) } } } if s.MatchParam == nil { s.MatchParam = new(serverproto.MatchParam) } if s.CustomParam == nil { s.CustomParam = new(serverproto.CustomParam) } if s.RoomConfigSystem == nil { s.RoomConfigSystem = new(webapiproto.RoomConfigSystem) } gf := PlatformMgrSingleton.GetGameFree(args.Platform.IdStr, args.GF.GetId()) if gf != nil { s.CloseCtrl = gf.GetCloseCtrl() } return s } func (this *Scene) RobotIsLimit() bool { if this.robotLimit != 0 { if this.robotNum >= this.robotLimit { return true } } return false } func (this *Scene) GetPlayerGameCtx(snid int32) *PlayerGameCtx { if ctx, exist := this.gameCtx[snid]; exist { return ctx } return nil } // PlayerEnter 玩家进入场景 func (this *Scene) PlayerEnter(p *Player, pos int, ischangeroom bool) bool { logger.Logger.Infof("(this *Scene:%v) PlayerEnter(%v, %v) ", this.sceneId, p.SnId, pos) if this.dbGameFree == nil { return false } // 机器人数量限制 if p.IsRobot() && this.robotLimit != 0 { if this.robotNum+1 > this.robotLimit { logger.Logger.Warnf("(this *Scene:%v) PlayerEnter(%v) robot num limit(%v)", this.sceneId, p.SnId, this.robotLimit) return false } } // 非百人,设置座位 if !this.IsHundredScene() { if pos != -1 { if this.seats[pos] != nil { for i := 0; i < this.playerNum; i++ { if this.seats[i] == nil { p.pos = i this.seats[i] = p break } } } else { p.pos = pos this.seats[pos] = p } } else { for i := 0; i < this.playerNum; i++ { if this.seats[i] == nil { p.pos = i this.seats[i] = p break } } } } // 如果正在等待比赛,退赛 if !this.IsMatchScene() { isWaiting, tmid := TournamentMgr.IsMatchWaiting(p.Platform, p.SnId) if isWaiting { TournamentMgr.CancelSignUp(p.Platform, tmid, p.SnId) } } takeCoin := p.Coin leaveCoin := int64(0) gameTimes := rand.Int31n(100) if this.IsCustom() { // 房卡场初始1000金币 takeCoin = 1000 } var matchParams []int32 //排名、段位、假snid、假角色、假皮肤 if this.IsMatchScene() && p.matchCtx != nil { takeCoin = int64(p.matchCtx.grade) matchParams = append(matchParams, p.matchCtx.rank) //排名 if p.IsRob { matchParams = append(matchParams, p.matchCtx.copyLv) //机器人随机段位 } else { matchParams = append(matchParams, 1) //段位默认值 } matchParams = append(matchParams, p.matchCtx.copySnid) //假snid matchParams = append(matchParams, p.matchCtx.copyRoleId) //假RoleId matchParams = append(matchParams, p.matchCtx.copySkinId) //假SkinId } if p.IsRob { this.robotNum++ p.RobotRandName() p.RandRobotVip(this) //随机机器人宠物技能等级 p.RandRobotPetSkillLevel() name := this.GetSceneName() logger.Logger.Tracef("(this *Scene) PlayerEnter(%v) robot(%v) robotlimit(%v)", name, this.robotNum, this.robotLimit) if !this.IsMatchScene() && !this.IsCustom() { flag := false // 本地游戏机器人携带金币 if common.IsLocalGame(this.gameId) { baseScore := this.BaseScore arrs := srvdata.PBDB_CreateroomMgr.Datas.Arr var tmpIds []int32 for i := 0; i < len(arrs); i++ { arr := arrs[i] if int(arr.GameId) == this.gameId && arr.GameSite == this.dbGameFree.GetSceneType() { betRange := arr.GetBetRange() if len(betRange) == 0 { continue } for j := 0; j < len(betRange); j++ { if betRange[j] == baseScore && len(arr.GetGoldRange()) > 0 && arr.GetGoldRange()[0] != 0 { tmpIds = append(tmpIds, arr.GetId()) break } } } } if len(tmpIds) > 0 { randId := common.RandInt32Slice(tmpIds) crData := srvdata.PBDB_CreateroomMgr.GetData(randId) if crData != nil { goldRange := crData.GetGoldRange() if len(goldRange) == 2 { takeCoin = common.RandFromRangeInt64(int64(goldRange[0]), int64(goldRange[1])) flag = true } else if len(goldRange) == 1 { takeCoin = common.RandFromRangeInt64(int64(goldRange[0]), 2*int64(goldRange[0])) flag = true } leaveCoin = int64(goldRange[0]) for _, id := range tmpIds { tmp := srvdata.PBDB_CreateroomMgr.GetData(id).GetGoldRange() if int64(tmp[0]) < leaveCoin && tmp[0] != 0 { leaveCoin = int64(tmp[0]) } } } } else { logger.Logger.Warn("gameId: ", this.gameId, " gameSite: ", this.dbGameFree.GetSceneType(), " BaseScore: ", baseScore) } if leaveCoin > takeCoin { logger.Logger.Warn("robotSnId: ", p.SnId, " BaseScore: ", baseScore, " takeCoin: ", takeCoin, " leaveCoin: ", leaveCoin) } if takeCoin > p.Coin { p.Coin = takeCoin } } // 非本地游戏机器人携带金币 if !flag { takerng := this.dbGameFree.GetRobotTakeCoin() if len(takerng) >= 2 && takerng[1] > takerng[0] { if takerng[0] < this.dbGameFree.GetLimitCoin() { takerng[0] = this.dbGameFree.GetLimitCoin() } takeCoin = int64(common.RandInt(int(takerng[0]), int(takerng[1]))) } else { maxlimit := int64(this.dbGameFree.GetMaxCoinLimit()) if maxlimit != 0 && p.Coin > maxlimit { logger.Logger.Trace("Player coin:", p.Coin) //在下限和上限之间随机,并对其的100的整数倍 takeCoin = int64(common.RandInt(int(this.dbGameFree.GetLimitCoin()), int(maxlimit))) logger.Logger.Trace("Take coin:", takeCoin) } if maxlimit == 0 && this.IsCoinScene() { maxlimit = int64(common.RandInt(10, 50)) * int64(this.dbGameFree.GetLimitCoin()) takeCoin = int64(common.RandInt(int(this.dbGameFree.GetLimitCoin()), int(maxlimit))) logger.Logger.Trace("Take coin:", takeCoin) } } takeCoin = takeCoin / 100 * 100 //离场金币 leaverng := this.dbGameFree.GetRobotLimitCoin() if len(leaverng) >= 2 { leaveCoin = leaverng[0] + rand.Int63n(leaverng[1]-leaverng[0]) } } // 象棋积分 chessScore := this.dbGameFree.GetChessScoreParams() if len(chessScore) == 2 { p.ChessGrade = int64(common.RandInt(int(chessScore[0]), int(chessScore[1]))) } if takeCoin > p.Coin { p.Coin = takeCoin } } } data, err := p.MarshalData() if err != nil { logger.Logger.Errorf("Scene PlayerEnter MarshalData failed, err:%v", err) return false } var gateSid int64 if p.gateSess != nil { if srvInfo, ok := p.gateSess.GetAttribute(srvlib.SessionAttributeServerInfo).(*srvlibproto.SSSrvRegiste); ok && srvInfo != nil { sessionId := srvlib.NewSessionIdEx(srvInfo.GetAreaId(), srvInfo.GetType(), srvInfo.GetId(), 0) gateSid = sessionId.Get() } } msg := &serverproto.WGPlayerEnter{ Sid: proto.Int64(p.sid), GateSid: proto.Int64(gateSid), SceneId: proto.Int(this.sceneId), PlayerData: data, TakeCoin: takeCoin, IsLoaded: proto.Bool(ischangeroom), IsQM: false, ExpectLeaveCoin: leaveCoin, ExpectGameTimes: gameTimes, IParams: p.MarshalIParam(), SParams: p.MarshalSParam(), CParams: p.MarshalCParam(), SnId: proto.Int32(p.SnId), Pos: int32(p.pos), MatchParams: matchParams, } // 道具 msg.Items = make(map[int32]int64) dbItemArr := srvdata.GameItemMgr.GetArr(p.Platform) for _, dbItem := range dbItemArr { msg.Items[dbItem.Id] = 0 itemInfo := BagMgrSingleton.GetItem(p.SnId, dbItem.Id) if itemInfo != nil { msg.Items[dbItem.Id] = itemInfo.ItemNum } } // 排位积分 ret := RankMgrSingleton.GetPlayerSeason(p.SnId) if ret != nil && ret.PlayerRankSeason != nil { msg.RankScore = make(map[int32]int64) for k, v := range ret.RankType { if v != nil { msg.RankScore[k] = v.Score } } } if p.IsRobot() { msg.RankScore = make(map[int32]int64) rankScore := this.dbGameFree.GetRankScoreParams() if len(rankScore) == 2 { switch { case this.dbGameFree.GameDif == common.GameDifTienlen: msg.RankScore[tienlen.RankType] = int64(common.RandInt(int(rankScore[0]), int(rankScore[1]))) } } } this.SendToGame(int(serverproto.SSPacketID_PACKET_WG_PLAYERENTER), msg) logger.Logger.Tracef("SSPacketID_PACKET_WG_PLAYERENTER Scene:%v ;PlayerEnter(%v, %v)", this.sceneId, p.SnId, pos) p.scene = this p.takeCoin = takeCoin p.sceneCoin = takeCoin p.enterts = time.Now() this.players[p.SnId] = p if !p.IsRob { //保存下进入时的环境 this.gameCtx[p.SnId] = &PlayerGameCtx{ takeCoin: p.takeCoin, enterTs: p.enterts.Unix(), } this.lastTime = time.Now() } this.gameSess.AddPlayer(p) this.sp.OnPlayerEnter(this, p.SnId) return true } func (this *Scene) AudienceEnter(p *Player, ischangeroom bool) bool { logger.Logger.Infof("(this *Scene:%v) AudienceEnter(%v) ", this.sceneId, p.SnId) p.scene = this takeCoin := p.Coin p.takeCoin = takeCoin this.audiences[p.SnId] = p this.gameSess.AddPlayer(p) data, err := p.MarshalData() if err != nil { return false } var gateSid int64 if p.gateSess != nil { if srvInfo, ok := p.gateSess.GetAttribute(srvlib.SessionAttributeServerInfo).(*srvlibproto.SSSrvRegiste); ok && srvInfo != nil { sessionId := srvlib.NewSessionIdEx(srvInfo.GetAreaId(), srvInfo.GetType(), srvInfo.GetId(), 0) gateSid = sessionId.Get() } } msg := &serverproto.WGPlayerEnter{ Sid: proto.Int64(p.sid), SnId: proto.Int32(p.SnId), GateSid: proto.Int64(gateSid), SceneId: proto.Int(this.sceneId), PlayerData: data, TakeCoin: takeCoin, IsLoaded: proto.Bool(ischangeroom), IParams: p.MarshalIParam(), SParams: p.MarshalSParam(), CParams: p.MarshalCParam(), } if !p.IsRob { //保存下进入时的环境 p.enterts = time.Now() this.gameCtx[p.SnId] = &PlayerGameCtx{ takeCoin: p.takeCoin, enterTs: p.enterts.Unix(), } this.lastTime = time.Now() } this.SendToGame(int(serverproto.SSPacketID_PACKET_WG_AUDIENCEENTER), msg) return true } func (this *Scene) lastScene(p *Player) { // 记录玩家在每个游戏场次最后进入的房间号 // 只记录金币场 if this.IsCoinScene() { const MINHOLD = 10 const MAXHOLD = 20 holdCnt := MINHOLD if this.csp != nil { holdCnt = this.csp.GetHasTruePlayerSceneCnt() + 2 if holdCnt < MINHOLD { holdCnt = MINHOLD } if holdCnt > MAXHOLD { holdCnt = MAXHOLD } } if p.lastSceneId == nil { p.lastSceneId = make(map[int32][]int32) } id := this.dbGameFree.GetId() if sceneIds, exist := p.lastSceneId[id]; exist { if !common.InSliceInt32(sceneIds, int32(this.sceneId)) { sceneIds = append(sceneIds, int32(this.sceneId)) cnt := len(sceneIds) if cnt > holdCnt { sceneIds = sceneIds[cnt-holdCnt:] } p.lastSceneId[id] = sceneIds } } else { p.lastSceneId[id] = []int32{int32(this.sceneId)} } } } func (this *Scene) DelPlayer(p *Player) bool { if p.scene != this { roomId := 0 if p.scene != nil { roomId = p.scene.sceneId } logger.Logger.Errorf("DelPlayer found player:%v in room:%v but room:%v", p.SnId, roomId, this.sceneId) } if this.gameSess != nil { this.gameSess.DelPlayer(p) } // 玩家离开游戏 if _, ok := this.players[p.SnId]; ok { delete(this.players, p.SnId) if p.IsRobot() { this.robotNum-- } // 记录玩家最近玩游戏的房间 this.lastScene(p) // 玩家最后所在游戏 p.LastGameId = int(this.dbGameFree.GetGameId()) } // 观众离开游戏 if _, ok := this.audiences[p.SnId]; ok { delete(this.audiences, p.SnId) } for k, v := range this.seats { if v != nil && v.SnId == p.SnId { p.pos = -1 this.seats[k] = nil break } } if !p.IsRob { delete(this.gameCtx, p.SnId) } p.scene = nil if !p.IsRob { this.lastTime = time.Now() } this.sp.OnPlayerLeave(this, p.SnId) return true } // PlayerLeave 玩家离开 func (this *Scene) PlayerLeave(p *Player, reason int) { logger.Logger.Infof("(this *Scene:%v) PlayerLeave(%v, %v) ", this.sceneId, p.SnId, reason) pack := &hallproto.SCQuitGame{ Id: this.dbGameFree.Id, Reason: proto.Int(reason), } pack.OpCode = hallproto.OpResultCode_Game_OPRC_Sucess_Game p.SendToClient(int(hallproto.GameHallPacketID_PACKET_SC_QUITGAME), pack) logger.Logger.Tracef("SCQuitGame: %v, %v", p.SnId, pack) this.DelPlayer(p) } // AudienceLeave 观众离开 func (this *Scene) AudienceLeave(p *Player, reason int) { logger.Logger.Infof("(this *Scene:%v) AudienceLeave(%v, %v) ", this.sceneId, p.SnId, reason) pack := &hallproto.SCLeaveRoom{ Reason: proto.Int(reason), OpRetCode: hallproto.OpResultCode_Game_OPRC_Sucess_Game, Mode: proto.Int(0), RoomId: proto.Int(this.sceneId), } p.SendToClient(int(hallproto.GameHallPacketID_PACKET_SC_LEAVEROOM), pack) logger.Logger.Tracef("AudienceLeave SCLeaveRoom: %v, %v", p.SnId, pack) this.DelPlayer(p) } // AudienceSit 观众坐下 func (this *Scene) AudienceSit(p *Player, pos int) bool { logger.Logger.Infof("(this *Scene:%v) AudienceSit(%v, %v, %v) ", this.sceneId, p.SnId, pos, this.dbGameFree.GetId()) if _, exist := this.audiences[p.SnId]; exist { delete(this.audiences, p.SnId) p.scene = this p.takeCoin = p.Coin this.players[p.SnId] = p msg := &serverproto.WGAudienceSit{ SnId: proto.Int32(p.SnId), TakeCoin: p.Coin, SceneId: proto.Int(this.sceneId), Pos: proto.Int(pos), } this.SendToGame(int(serverproto.SSPacketID_PACKET_WG_AUDIENCESIT), msg) if !p.IsRob { this.lastTime = time.Now() } return true } return false } func (this *Scene) HasPlayer(p *Player) bool { if _, exist := this.players[p.SnId]; exist { return true } return false } func (this *Scene) HasAudience(p *Player) bool { if _, exist := this.audiences[p.SnId]; exist { return true } return false } func (this *Scene) GetPlayer(id int32) *Player { if p, exist := this.players[id]; exist { return p } return nil } func (this *Scene) GetAudience(id int32) *Player { if p, exist := this.audiences[id]; exist { return p } return nil } func (this *Scene) GetPlayerPos(snId int32) int { for index, value := range this.seats { if value == nil { continue } if value.SnId == snId { return index } } return -1 } func (this *Scene) GetPlayerCnt() int { return len(this.players) } func (this *Scene) GetMaxPlayerNum() int { return this.playerNum } func (this *Scene) GetAudienceCnt() int { return len(this.audiences) } // IsFull 是否满人 // 不包含观众 func (this *Scene) IsFull() bool { if this.playerNum == 0 { return false } return this.GetPlayerCnt() >= this.playerNum } func (this *Scene) IsEmpty() bool { return this.GetPlayerCnt() == 0 } func (this *Scene) AllIsRobot() bool { return len(this.players) == this.robotNum } // OnClose 房间销毁 func (this *Scene) OnClose() { scDestroyRoom := &hallproto.SCDestroyRoom{ RoomId: proto.Int(this.sceneId), OpRetCode: hallproto.OpResultCode_Game_OPRC_Sucess_Game, IsForce: proto.Int(1), } this.Broadcast(int(hallproto.GameHallPacketID_PACKET_SC_DESTROYROOM), scDestroyRoom, 0) this.deleting = true this.closed = true for _, p := range this.players { this.DelPlayer(p) } for _, p := range this.audiences { this.DelPlayer(p) } this.players = nil this.audiences = nil this.gameSess = nil } func (this *Scene) SendToGame(packetId int, pack interface{}) bool { if this.gameSess != nil { this.gameSess.Send(packetId, pack) return true } return false } // IsLongTimeInactive 房间是否长时间没有活动 func (this *Scene) IsLongTimeInactive() bool { tNow := time.Now() // 房间没有真人,没有观众,长时间没有真人进出房间 if this.GetTruePlayerCnt() == 0 && this.GetAudienceCnt() == 0 && tNow.Sub(this.lastTime) > time.Second*time.Duration(model.GameParamData.SceneMaxIdle) { return true } return false } func (this *Scene) SendGameDestroy(isGrace bool) { if !isGrace { this.deleting = true this.force = true } pack := &serverproto.WGDestroyScene{ Ids: []int64{int64(this.sceneId)}, IsGrace: isGrace, } this.SendToGame(int(serverproto.SSPacketID_PACKET_WG_DESTROYSCENE), pack) logger.Logger.Tracef("WG_DESTROYSCENE: %v", pack) } // IsCoinScene 金币场 func (this *Scene) IsCoinScene() bool { return this != nil && this.csp != nil } // IsHundredScene 百人场 func (this *Scene) IsHundredScene() bool { return this != nil && this.hp != nil } // IsMatchScene 比赛场 func (this *Scene) IsMatchScene() bool { return this.IsSceneMode(common.SceneModeMatch) } // IsPrivateScene 私人房间 func (this *Scene) IsPrivateScene() bool { return this.IsSceneMode(common.SceneModePrivate) } // IsCustom 竞技馆房间 func (this *Scene) IsCustom() bool { if this.IsSceneMode(common.SceneModePrivateMatch) { return true } if this.dbGameFree == nil { return false } return this.dbGameFree.IsCustom > 0 } // IsRankMatch 排位赛 func (this *Scene) IsRankMatch() bool { if this.dbGameFree == nil { return false } return this.dbGameFree.RankType > 0 } // IsSceneMode 房间模式 func (this *Scene) IsSceneMode(mode int) bool { return this.sceneMode == mode } // IsTestScene 试玩场 func (this *Scene) IsTestScene() bool { if this.dbGameFree != nil { return this.dbGameFree.GetSceneType() == -1 } return false } func (this *Scene) GetSceneName() string { if this.dbGameFree != nil { return this.dbGameFree.GetName() + this.dbGameFree.GetTitle() } return "[unknow scene name]" } func (this *Scene) IsPlatform(platform string) bool { if platform == "0" || platform == this.platform.IdStr { return true } return false } func (this *Scene) GetWhitePlayerCnt() int { var cnt int for _, p := range this.players { if p.WBLevel > 0 { cnt++ } } return cnt } func (this *Scene) GetBlackPlayerCnt() int { var cnt int for _, p := range this.players { if p.WBLevel < 0 { cnt++ } } return cnt } func (this *Scene) GetLostPlayerCnt() int { var cnt int keyGameId := strconv.Itoa(int(this.dbGameFree.GetGameId())) for _, p := range this.players { if p.GDatas != nil { if d, exist := p.GDatas[keyGameId]; exist { if d.Statics.TotalIn > d.Statics.TotalOut { cnt++ } } } } return cnt } func (this *Scene) GetWinPlayerCnt() int { var cnt int keyGameId := strconv.Itoa(int(this.dbGameFree.GetGameId())) for _, p := range this.players { if p.GDatas != nil { if d, exist := p.GDatas[keyGameId]; exist { if d.Statics.TotalIn < d.Statics.TotalOut { cnt++ } } } } return cnt } func (this *Scene) GetTruePlayerCnt() int { return len(this.players) - this.robotNum } func (this *Scene) Broadcast(packetId int, msg rawproto.Message, excludeSid int64) { mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion) for _, p := range this.players { if p != nil { if p.sid != excludeSid { if p.gateSess != nil && p.IsOnLine() { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: p.sid, }, }) } } } } for _, p := range this.audiences { if p != nil && p.sid != excludeSid { if p.gateSess != nil && p.IsOnLine() { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: p.sid, }, }) } } } for gateSess, v := range mgs { if gateSess != nil && len(v) != 0 { action.MulticastMessageToServer(gateSess, packetId, msg, v...) } } } func (this *Scene) HasSameIp(ip string) bool { for _, p := range this.players { if !p.IsRob { if p.Ip == ip { return true } } } return false } func (this *Scene) IsPreCreateScene() bool { return this.dbGameFree.GetCreateRoomNum() > 0 } // todo 删除 func (this *Scene) TryForceDeleteMatchInfo() { if !this.IsMatchScene() { return } if len(this.players) == 0 { return } if this.MatchSortId == 0 { return } if players, exist := TournamentMgr.players[this.MatchSortId]; exist { for _, player := range this.players { if player != nil && !player.IsRob { if TournamentMgr.IsGaming(player.SnId) { delete(players, player.SnId) } } } } } // CanAudience 是否允许观战 func (this *Scene) CanAudience() bool { switch { case this.GetMatchSortId() > 0: // 比赛场 tm := TournamentMgr.GetTm(this.GetMatchSortId()) if tm != nil { return tm.gmd.GetAudienceSwitch() == 1 } return false default: return true } } func (this *Scene) ProtoPrivateRoom() *gamehall.PrivateRoomInfo { if !this.IsCustom() { return nil } needPassword := int32(0) if this.GetPassword() != "" { needPassword = int32(1) } ret := &gamehall.PrivateRoomInfo{ GameFreeId: this.dbGameFree.GetId(), GameId: int32(this.gameId), RoomTypeId: this.RoomTypeId, RoomConfigId: this.CustomParam.GetRoomConfigId(), RoomId: int32(this.sceneId), NeedPassword: needPassword, CurrRound: this.currRound, MaxRound: this.totalRound, CurrNum: int32(this.GetPlayerCnt()), MaxPlayer: int32(this.playerNum), CreateTs: this.createTime.Unix(), State: this.SceneState, CostType: this.CustomParam.GetCostType(), } for _, v := range this.players { ret.Players = append(ret.Players, &gamehall.PrivatePlayerInfo{ SnId: v.SnId, Name: v.Name, UseRoleId: v.GetRoleId(), }) } if this.CustomWinSnId > 0 { p := PlayerMgrSington.GetPlayerBySnId(this.CustomWinSnId) if p != nil { ret.WinSnId = p.SnId ret.WinName = p.GetName() ret.WinRoleId = p.Roles.ModId } } return ret } // NotifyPrivateRoom 通知私人房列表变更 func (this *Scene) NotifyPrivateRoom(tp common.ListOpType) { if this.IsCustom() { pack := &gamehall.SCGetPrivateRoomList{ Tp: int32(tp), Datas: []*gamehall.PrivateRoomInfo{this.ProtoPrivateRoom()}, } PlayerNotifySingle.SendToClient(common.NotifyPrivateRoomList, this.platform.IdStr, int(gamehall.GameHallPacketID_PACKET_SC_GETPRIVATEROOMLIST), pack) logger.Logger.Tracef("NotifyPrivateRoom: %v", pack) } }