452 lines
12 KiB
Go
452 lines
12 KiB
Go
package main
|
||
|
||
import (
|
||
"mongo.games.com/goserver/core/logger"
|
||
|
||
"mongo.games.com/game/common"
|
||
"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
|
||
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, 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,
|
||
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) ID() int32 {
|
||
return csp.dbGameFree.Id
|
||
}
|
||
|
||
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 获取场次类型
|
||
// 新手场,中级场 ...
|
||
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
|
||
}
|
||
|
||
// PreCreateRoom 预创建房间
|
||
func (csp *CoinScenePool) PreCreateRoom() {
|
||
if csp.platform == DefaultPlatform || model.GameParamData.ClosePreCreateRoom {
|
||
return
|
||
}
|
||
if p := PlatformMgrSingleton.GetPlatform(csp.platform); p == nil || p.Disable {
|
||
return
|
||
}
|
||
preCreateNum := int(csp.dbGameFree.GetCreateRoomNum())
|
||
if preCreateNum <= 0 {
|
||
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
|
||
}
|
||
|
||
// GetHasTruePlayerSceneCnt 有真人的房间数量
|
||
func (csp *CoinScenePool) GetHasTruePlayerSceneCnt() int {
|
||
cnt := 0
|
||
for _, s := range csp.scenes {
|
||
if s.GetTruePlayerCnt() != 0 {
|
||
cnt++
|
||
}
|
||
}
|
||
return cnt
|
||
}
|
||
|
||
// AddScene 添加房间
|
||
// 自定义房间参数的时候创建房间后添加到房间池
|
||
// 创建房间后,调用AddScene添加到房间池,在玩家进入房间之前调用
|
||
func (csp *CoinScenePool) AddScene(s *Scene) {
|
||
if s == nil {
|
||
return
|
||
}
|
||
csp.scenes[s.sceneId] = s
|
||
s.csp = csp
|
||
}
|
||
|
||
// 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)
|
||
}
|
||
|
||
// 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
|
||
}
|
||
|
||
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 {
|
||
logger.Logger.Infof("(csp *CoinScenePool) PlayerEnter create new scene:%v snid:%v gamefreeid:%v", scene.sceneId, p.SnId, csp.ID())
|
||
csp.AddScene(scene)
|
||
} else {
|
||
logger.Logger.Errorf("Create %v scene failed.", csp.ID())
|
||
}
|
||
}
|
||
|
||
if scene != nil {
|
||
if scene.PlayerEnter(p, -1, isChangeRoom) {
|
||
logger.Logger.Infof("(csp *CoinScenePool) PlayerEnter snid:%v sceneid:%v gamefreeid:%v success", p.SnId, scene.sceneId, csp.ID())
|
||
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
|
||
}
|
||
|
||
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) {
|
||
logger.Logger.Infof("(csp *CoinScenePool) AudienceEnter snid:%v sceneid:%v gamefreeid:%v success", p.SnId, scene.sceneId, csp.ID())
|
||
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)
|
||
}
|
||
|
||
// 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.SendGameDestroy(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.SendGameDestroy(false)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// playerLeave 玩家离开房间
|
||
func (csp *CoinScenePool) playerLeave(p *Player, reason int) bool {
|
||
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 {
|
||
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
|
||
}
|
||
|
||
// onDestroyScene 解散房间
|
||
// 房间解散一定是游戏服确认的,worldsrv收到游戏房间解散消息后解散房间,此时房间内玩家应该都离开了
|
||
// 或者游戏服异常断开触发房间解散,此时房间中还有人
|
||
func (csp *CoinScenePool) onDestroyScene(sceneId int) {
|
||
scene, ok := csp.scenes[sceneId]
|
||
if !ok || scene == nil {
|
||
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)
|
||
for k := range scene.players {
|
||
delete(csp.players, k)
|
||
}
|
||
for k := range scene.audiences {
|
||
delete(csp.players, k)
|
||
}
|
||
scene.csp = nil // 解除关联
|
||
delete(csp.scenes, sceneId)
|
||
CoinSceneMgrSingleton.TouchCreateRoom(csp.platform, csp.dbGameFree.Id)
|
||
}
|