game_sync/worldsrv/coinscenepool.go

503 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"mongo.games.com/game/common"
"mongo.games.com/goserver/core/logger"
"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
groupId int32 // 组id
id int32 // 场次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, groupId int32, 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,
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) 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)
}
// AddScene 添加房间
func (csp *CoinScenePool) AddScene(s *Scene) {
if s == nil {
return
}
csp.scenes[s.sceneId] = s
s.csp = csp
if csp.groupId != 0 {
CoinSceneMgrSingleton.groupOfScene[s.sceneId] = csp.groupId
} else {
CoinSceneMgrSingleton.platformOfScene[s.sceneId] = csp.platform
}
}
// 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
}
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 gamehallproto.OpResultCode_OPRC_Error
}
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 {
csp.AddScene(scene)
} else {
logger.Logger.Errorf("Create %v scene failed.", csp.id)
}
}
if scene != nil {
if scene.PlayerEnter(p, -1, isChangeRoom) {
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
}
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 gamehallproto.OpResultCode_OPRC_Error
}
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) {
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)
}
// 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.DoDelete(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.DoDelete(false)
}
}
}
}
// OnDestroyScene 解散房间
// 房间解散一定是游戏服确认的worldsrv收到游戏房间解散消息后解散房间
func (csp *CoinScenePool) OnDestroyScene(sceneId int) {
scene, ok := csp.scenes[sceneId]
if !ok {
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)
scene.csp = nil // 解除关联
delete(csp.scenes, sceneId)
CoinSceneMgrSingleton.TouchCreateRoom(csp.platform, csp.dbGameFree.Id)
}
// PreCreateRoom 预创建房间
func (csp *CoinScenePool) PreCreateRoom() {
if csp.platform == DefaultPlatform {
return
}
if p := PlatformMgrSingleton.GetPlatform(csp.platform); p == nil || p.Disable {
return
}
preCreateNum := int(csp.dbGameFree.GetCreateRoomNum())
if preCreateNum <= 0 || model.GameParamData.ClosePreCreateRoom {
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
}
// 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
// }
//
// if len(csp.scenes) == 0 {
// return false
// }
//
// pack := &gamehallproto.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 := &gamehallproto.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(gamehallproto.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
}