game_sync/worldsrv/coinscenepool.go

468 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/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.SceneModePublic)
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
}
}
// 具体场次的入场规则
canEnterFunc := GetCoinSceneCanEnterFunc(int(dbGameFree.GetGameId()))
if canEnterFunc != nil {
ret := canEnterFunc(csp, p)
if ret != gamehallproto.OpResultCode_OPRC_Sucess {
return ret
}
}
// 通用入场检测
if dbGameFree.GetLimitCoin() != 0 && dbGameFree.GetLimitCoin() > p.Coin && !p.IsRob {
return gamehallproto.OpResultCode_OPRC_CoinNotEnough
}
if dbGameFree.GetMaxCoinLimit() != 0 && dbGameFree.GetMaxCoinLimit() < p.Coin && !p.IsRob {
return gamehallproto.OpResultCode_OPRC_CoinTooMore
}
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 s.sp.CanEnter(s, p.SnId) == 0 {
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, s.sp.CanEnter(s, p.SnId))
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.platform.IdStr == scene.platform.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)
}