607 lines
16 KiB
Go
607 lines
16 KiB
Go
package main
|
|
|
|
import (
|
|
"math"
|
|
"slices"
|
|
"sort"
|
|
"strconv"
|
|
|
|
"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"
|
|
webapiproto "mongo.games.com/game/protocol/webapi"
|
|
)
|
|
|
|
func init() {
|
|
common.ClockMgrSingleton.RegisterSinker(SceneMgrSingleton)
|
|
}
|
|
|
|
var SceneMgrSingleton = &SceneMgr{
|
|
scenes: make(map[int]*Scene),
|
|
privateAutoId: common.PrivateSceneStartId,
|
|
matchAutoId: common.MatchSceneStartId,
|
|
coinSceneAutoId: common.CoinSceneStartId,
|
|
hundredSceneAutoId: common.HundredSceneStartId,
|
|
password: make(map[string]struct{}),
|
|
pushList: make(map[int]struct{}),
|
|
}
|
|
|
|
// SceneMgr 房间管理器
|
|
type SceneMgr struct {
|
|
common.BaseClockSinker // 驱动时间事件
|
|
scenes map[int]*Scene // 房间id: Scene
|
|
|
|
privateAutoId int // 私人房房间号
|
|
matchAutoId int // 比赛场房间号
|
|
coinSceneAutoId int // 金币场房间号
|
|
hundredSceneAutoId int // 百人场房间号
|
|
password map[string]struct{} // 密码
|
|
pushList map[int]struct{} // 已经推荐过的房间列表
|
|
lastPushSceneId int // 最后推荐的房间id
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func (m *SceneMgr) GenPassword() string {
|
|
for i := 0; i < 100; i++ {
|
|
s := strconv.Itoa(common.RandInt(100000, 1000000))
|
|
if _, ok := m.password[s]; !ok {
|
|
m.password[s] = struct{}{}
|
|
return s
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (m *SceneMgr) GetPlatformBySceneId(sceneId int) string {
|
|
s := m.GetScene(sceneId, true)
|
|
if s != nil && s.platform != nil {
|
|
return s.platform.IdStr
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetScene 获取房间对象
|
|
// 默认是不包含删除中的房间
|
|
// hasDeleting true 包含删除中的房间
|
|
func (m *SceneMgr) GetScene(sceneId int, hasDeleting ...bool) *Scene {
|
|
has := false
|
|
if len(hasDeleting) > 0 {
|
|
has = hasDeleting[0]
|
|
}
|
|
if s, exist := m.scenes[sceneId]; exist && (has || !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
|
|
}
|
|
|
|
// GetMatchRoom 获取比赛房间
|
|
// sortId 比赛id
|
|
func (m *SceneMgr) GetMatchRoom(sortId int64) []*Scene {
|
|
var scenes []*Scene
|
|
for _, value := range m.scenes {
|
|
if value.GetMatchSortId() == sortId {
|
|
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, isCustom bool, roomConfigId int32, start, end, pageSize int32) ([]*webapiproto.RoomInfo, int32, int32) {
|
|
roomInfo := make([]*webapiproto.RoomInfo, 0, len(m.scenes))
|
|
var isNeedFindAll = false
|
|
if model.GameParamData.IsFindRoomByGroup && platform != "" && snId != 0 && gameId == 0 &&
|
|
gameMode == 0 && sceneId == -1 && groupId == 0 && sceneMode == 0 {
|
|
p := PlayerMgrSington.GetPlayerBySnId(snId)
|
|
if p != nil && p.Platform == platform {
|
|
isNeedFindAll = true
|
|
}
|
|
}
|
|
for _, s := range m.scenes {
|
|
if (((s.platform != nil && s.platform.IdStr == platform) || platform == "") &&
|
|
((s.gameId == gameId && s.gameMode == gameMode) || gameId == 0) &&
|
|
(s.sceneId == sceneId || sceneId == 0) && (s.groupId == int32(groupId) || groupId == 0) &&
|
|
(s.dbGameFree.GetId() == gameFreeId || gameFreeId == 0) &&
|
|
(s.sceneMode == sceneMode || sceneMode == -1) &&
|
|
((s.IsCustom() && isCustom) || !isCustom) &&
|
|
(s.CustomParam.GetRoomConfigId() == roomConfigId || roomConfigId == 0)) || isNeedFindAll {
|
|
var platformName string
|
|
if s.platform != nil {
|
|
platformName = s.platform.IdStr
|
|
}
|
|
|
|
si := &webapiproto.RoomInfo{
|
|
Platform: platformName,
|
|
SceneId: int32(s.sceneId),
|
|
GameId: int32(s.gameId),
|
|
GameMode: int32(s.gameMode),
|
|
SceneMode: int32(s.sceneMode),
|
|
GroupId: s.groupId,
|
|
GameFreeId: s.dbGameFree.GetId(),
|
|
Creator: s.creator,
|
|
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,
|
|
RoomConfigId: s.CustomParam.GetRoomConfigId(),
|
|
CurrRound: s.currRound,
|
|
MaxRound: s.totalRound,
|
|
Password: s.GetPassword(),
|
|
CostType: s.CustomParam.GetCostType(),
|
|
Voice: s.CustomParam.GetVoice(),
|
|
PlayerNum: int32(s.playerNum),
|
|
}
|
|
if s.starting {
|
|
si.Start = 1
|
|
} else {
|
|
si.Start = 0
|
|
}
|
|
if s.IsHundredScene() {
|
|
si.Start = 1
|
|
}
|
|
if s.RoomConfigSystem.GetId() > 0 {
|
|
si.Creator = s.RoomConfigSystem.GetId()
|
|
}
|
|
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 == 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)
|
|
}
|
|
|
|
type FindRoomParam struct {
|
|
Platform string
|
|
GameId []int
|
|
GameMode []int
|
|
SceneMode []int
|
|
RoomId int32
|
|
IsCustom int32 // 房卡场
|
|
IsFree int32 // 自由桌
|
|
GameFreeId []int32 // 场次id
|
|
SnId int32 // 玩家id
|
|
IsMatch bool // 比赛场
|
|
IsRankMatch bool // 排位赛
|
|
Channel []string // 渠道
|
|
}
|
|
|
|
func (m *SceneMgr) FindRoomList(args *FindRoomParam) []*Scene {
|
|
ret := make([]*Scene, 0)
|
|
for _, v := range m.scenes {
|
|
if args.Platform != "" && v.platform.IdStr != args.Platform {
|
|
continue
|
|
}
|
|
if len(args.GameId) > 0 {
|
|
if !slices.Contains(args.GameId, int(v.dbGameFree.GetGameId())) {
|
|
continue
|
|
}
|
|
}
|
|
if len(args.GameMode) > 0 {
|
|
if !slices.Contains(args.GameMode, int(v.dbGameFree.GetGameMode())) {
|
|
continue
|
|
}
|
|
}
|
|
if len(args.SceneMode) > 0 {
|
|
if !slices.Contains(args.SceneMode, v.sceneMode) {
|
|
continue
|
|
}
|
|
}
|
|
if args.RoomId > 0 && v.sceneId != int(args.RoomId) {
|
|
continue
|
|
}
|
|
if args.IsCustom == 1 && v.dbGameFree.GetIsCustom() != args.IsCustom {
|
|
continue
|
|
}
|
|
if args.IsFree == 1 && v.dbGameFree.GetFreeMode() != args.IsFree {
|
|
continue
|
|
}
|
|
if len(args.GameFreeId) > 0 {
|
|
if !slices.Contains(args.GameFreeId, v.dbGameFree.GetId()) {
|
|
continue
|
|
}
|
|
}
|
|
if args.SnId > 0 && v.GetPlayer(args.SnId) == nil {
|
|
continue
|
|
}
|
|
if args.IsMatch && !v.IsMatchScene() {
|
|
continue
|
|
}
|
|
if args.IsRankMatch && !v.IsRankMatch() {
|
|
continue
|
|
}
|
|
if len(args.Channel) > 0 {
|
|
has := false
|
|
for _, vv := range args.Channel {
|
|
if slices.Contains(v.Channel, vv) {
|
|
has = true
|
|
break
|
|
}
|
|
}
|
|
if !has {
|
|
continue
|
|
}
|
|
}
|
|
|
|
if v.deleting || v.closed || v.force {
|
|
continue
|
|
}
|
|
|
|
ret = append(ret, v)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// FindCustomInviteRoom 竞技馆房间推荐
|
|
func (m *SceneMgr) FindCustomInviteRoom(p *Player) *Scene {
|
|
// 无密码,未满人,未开始
|
|
// 玩家房间 > 系统房间
|
|
// 人数 > 招募次数 > 创建时间
|
|
var ret []*Scene
|
|
for _, v := range m.scenes {
|
|
if v.deleting || v.force || v.closed {
|
|
continue
|
|
}
|
|
if !v.IsCustom() {
|
|
continue
|
|
}
|
|
if v.GetPassword() != "" {
|
|
continue
|
|
}
|
|
if v.IsFull() {
|
|
continue
|
|
}
|
|
if !v.IsRecruit {
|
|
continue
|
|
}
|
|
if len(v.Channel) > 0 && !slices.Contains(v.Channel, p.AppChannel) {
|
|
continue
|
|
}
|
|
ret = append(ret, v)
|
|
}
|
|
|
|
sort.Slice(ret, func(i, j int) bool {
|
|
if ret[i].creator > 0 && ret[j].creator == 0 {
|
|
return true
|
|
}
|
|
if ret[i].creator == 0 && ret[j].creator > 0 {
|
|
return false
|
|
}
|
|
iN, jN := ret[i].GetMaxPlayerNum()-ret[i].GetPlayerCnt(), ret[j].GetMaxPlayerNum()-ret[j].GetPlayerCnt()
|
|
if iN < jN {
|
|
return true
|
|
}
|
|
if iN > jN {
|
|
return false
|
|
}
|
|
if ret[i].RecruitTimes > ret[j].RecruitTimes {
|
|
return true
|
|
}
|
|
if ret[i].RecruitTimes < ret[j].RecruitTimes {
|
|
return false
|
|
}
|
|
return ret[i].createTime.Unix() < ret[j].createTime.Unix()
|
|
})
|
|
|
|
// 删除没有的房间
|
|
var list []*Scene
|
|
var pushList = map[int]struct{}{}
|
|
for k := range m.pushList {
|
|
var has bool
|
|
for _, v := range ret {
|
|
if v.sceneId == k {
|
|
has = true
|
|
break
|
|
}
|
|
}
|
|
if has {
|
|
pushList[k] = struct{}{}
|
|
}
|
|
}
|
|
m.pushList = pushList
|
|
|
|
// 删除推荐过的房间
|
|
for _, v := range ret {
|
|
if _, ok := m.pushList[v.sceneId]; !ok {
|
|
list = append(list, v)
|
|
}
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
m.pushList[list[0].sceneId] = struct{}{}
|
|
return list[0]
|
|
}
|
|
|
|
if len(ret) > 0 {
|
|
// 全都推荐过了,循环推荐房间
|
|
var b bool
|
|
for _, v := range ret {
|
|
if b {
|
|
m.lastPushSceneId = v.sceneId
|
|
return v
|
|
}
|
|
if v.sceneId == m.lastPushSceneId {
|
|
b = true
|
|
}
|
|
}
|
|
// 没找到,从头开始
|
|
m.lastPushSceneId = ret[0].sceneId
|
|
return ret[0]
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type CreateSceneParam struct {
|
|
CreateId int32 // 创建者id
|
|
RoomId int // 房间id
|
|
SceneMode int // 公共,私人,赛事
|
|
CycleTimes int // 循环次数
|
|
TotalRound int // 总轮数
|
|
Params []int64 // 房间参数
|
|
GS *GameSession // 游戏服务
|
|
Platform *Platform // 所在平台
|
|
GF *serverproto.DB_GameFree // 场次配置
|
|
PlayerNum int32 // 玩家最大数量
|
|
BaseScore int32 // 底分
|
|
Channel []string // 客户端类型,允许查看的客户端类型
|
|
*serverproto.CustomParam // 房卡场参数
|
|
*serverproto.MatchParam // 比赛场参数
|
|
*webapiproto.RoomConfigSystem // 竞技管系统房参数
|
|
IsRecruit bool // 是否招募
|
|
}
|
|
|
|
// CreateScene 创建房间
|
|
func (m *SceneMgr) CreateScene(args *CreateSceneParam) *Scene {
|
|
logger.Logger.Tracef("SceneMgr NewScene %v", args)
|
|
if args.GF == nil {
|
|
return nil
|
|
}
|
|
if args.Platform == nil {
|
|
return nil
|
|
}
|
|
if args.GS == nil {
|
|
args.GS = GameSessMgrSington.GetMinLoadSess(int(args.GF.GetGameId()))
|
|
}
|
|
if args.GS == nil {
|
|
return nil
|
|
}
|
|
|
|
// 创建房间
|
|
s := NewScene(args)
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
m.scenes[args.RoomId] = s
|
|
// 添加到游戏服记录中
|
|
args.GS.AddScene(&AddSceneParam{
|
|
S: s,
|
|
})
|
|
s.sp.OnStart(s)
|
|
logger.Logger.Infof("SceneMgr NewScene Platform:%v %+v", args.Platform.IdStr, args)
|
|
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
|
|
}
|
|
|
|
s.sp.OnStop(s)
|
|
s.gameSess.DelScene(s)
|
|
switch {
|
|
case s.IsCoinScene():
|
|
CoinSceneMgrSingleton.OnDestroyScene(s.sceneId)
|
|
|
|
case s.IsHundredScene():
|
|
HundredSceneMgrSingleton.OnDestroyScene(s.sceneId)
|
|
}
|
|
s.OnClose()
|
|
|
|
delete(m.scenes, s.sceneId)
|
|
delete(m.password, s.GetPassword())
|
|
logger.Logger.Infof("(this *SceneMgr) DestroyScene, SceneId=%v", sceneId)
|
|
}
|
|
|
|
// SendGameDestroy 发送游戏服销毁房间
|
|
func (m *SceneMgr) SendGameDestroy(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)
|
|
}
|
|
|
|
// CheckDestroyEmptyRoom 尝试解散空闲房间
|
|
// 非必须,防止内存泄露
|
|
func (m *SceneMgr) CheckDestroyEmptyRoom() {
|
|
for _, s := range m.scenes {
|
|
switch {
|
|
case s.IsCoinScene():
|
|
if !s.IsLongTimeInactive() {
|
|
continue
|
|
}
|
|
if s.dbGameFree == nil {
|
|
continue
|
|
}
|
|
if s.dbGameFree.GetCreateRoomNum() == 0 {
|
|
logger.Logger.Warnf("SceneMgr.DeleteLongTimeInactive CoinScene SendGameDestroy scene:%v IsLongTimeInactive", s.sceneId)
|
|
s.SendGameDestroy(false)
|
|
}
|
|
if s.dbGameFree.GetCreateRoomNum() > 0 && s.csp.GetRoomNum(common.SceneModePublic) > int(s.dbGameFree.GetCreateRoomNum()) {
|
|
logger.Logger.Warnf("SceneMgr.DeleteLongTimeInactive CoinScene SendGameDestroy scene:%v IsLongTimeInactive", s.sceneId)
|
|
s.SendGameDestroy(false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=========================ClockSinker===============================
|
|
|
|
// InterestClockEvent 接收所有时间事件
|
|
func (m *SceneMgr) InterestClockEvent() int {
|
|
return 1 << common.ClockEventMinute
|
|
}
|
|
|
|
func (m *SceneMgr) OnMiniTimer() {
|
|
m.CheckDestroyEmptyRoom()
|
|
}
|