game_sync/worldsrv/coinscenemgr.go

588 lines
17 KiB
Go

package main
import (
"math/rand"
"time"
"mongo.games.com/goserver/core"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module"
"mongo.games.com/goserver/core/transact"
"mongo.games.com/game/common"
"mongo.games.com/game/proto"
hall_proto "mongo.games.com/game/protocol/gamehall"
"mongo.games.com/game/protocol/server"
"mongo.games.com/game/protocol/webapi"
"mongo.games.com/game/srvdata"
)
var CoinSceneMgrSingleton = &CoinSceneMgr{
playerChanging: make(map[int32]int32),
//按平台管理
scenesOfPlatform: make(map[string]map[int32]*CoinScenePool),
platformOfScene: make(map[int]string),
//按组管理
scenesOfGroup: make(map[int32]map[int32]*CoinScenePool),
groupOfScene: make(map[int]int32),
}
type CreateRoomCache struct {
gameFreeId int32
platformName string
}
type CoinSceneMgr struct {
playerChanging map[int32]int32 // snid:gamefreeid 换桌中的玩家
//按平台管理
scenesOfPlatform map[string]map[int32]*CoinScenePool // platform:gamefreeid
platformOfScene map[int]string // sceneid:platform; 创建房间后记录房间所在平台
//按组管理
scenesOfGroup map[int32]map[int32]*CoinScenePool // groupid:gamefreeid
groupOfScene map[int]int32 // sceneid:groupid;
//延迟创建房间列表
delayCache []*CreateRoomCache // 待预创建房间
}
// GetCoinScenePool 获取一个场景池
// plt 平台id
// id 场次id
func (csm *CoinSceneMgr) GetCoinScenePool(plt string, id int32) *CoinScenePool {
gf := PlatformMgrSingleton.GetGameFree(plt, id)
if gf == nil {
return nil
}
groupId := gf.GetGroupId()
if groupId != 0 {
if _, ok := csm.scenesOfGroup[groupId]; ok {
if csp, ok := csm.scenesOfGroup[groupId][id]; ok {
return csp
}
}
} else {
if ss, ok := csm.scenesOfPlatform[plt]; ok {
if csp, ok := ss[id]; ok && csp != nil {
return csp
}
}
}
if gf.GetDbGameFree() == nil {
return nil
}
// 创建了一个新的
// 应该是走不到这里,因为模块启动时所有场次都创建了房间池
pool := newCoinScenePool(plt, groupId, gf.GetDbGameFree())
if groupId != 0 {
v, ok := csm.scenesOfGroup[groupId]
if !ok || v == nil {
csm.scenesOfGroup[groupId] = make(map[int32]*CoinScenePool)
}
csm.scenesOfGroup[groupId][id] = pool
} else {
v, ok := csm.scenesOfPlatform[plt]
if !ok || v == nil {
csm.scenesOfPlatform[plt] = make(map[int32]*CoinScenePool)
}
csm.scenesOfPlatform[plt][id] = pool
}
return pool
}
func (csm *CoinSceneMgr) findCoinScenePool(platform string, id int32) (pools map[int32]*CoinScenePool, groupID int32,
dbGameFree *server.DB_GameFree) {
gf := PlatformMgrSingleton.GetGameFree(platform, id)
if gf == nil || gf.GetDbGameFree() == nil {
return nil, 0, nil
}
groupId := gf.GetGroupId()
var ss map[int32]*CoinScenePool
var ok bool
if groupId != 0 {
ss, ok = csm.scenesOfGroup[groupId]
if !ok {
ss = make(map[int32]*CoinScenePool)
csm.scenesOfGroup[groupId] = ss
}
return ss, groupId, gf.GetDbGameFree()
}
ss, ok = csm.scenesOfPlatform[platform]
if !ok {
ss = make(map[int32]*CoinScenePool)
csm.scenesOfPlatform[platform] = ss
}
return ss, 0, gf.GetDbGameFree()
}
// PlayerEnter 玩家进入房间池
func (csm *CoinSceneMgr) PlayerEnter(p *Player, id int32, roomId int32, exclude []int32, isChangeRoom bool) hall_proto.OpResultCode {
logger.Logger.Tracef("(csm *CoinSceneMgr) PlayerEnter snid:%v id:%v roomid:%v exclude:%v", p.SnId, id, roomId, exclude)
if p.isDelete { //删档用户不让进游戏
return hall_proto.OpResultCode_OPRC_RoomHadClosed
}
//多平台支持
platform := p.GetPlatform()
if platform == nil {
return hall_proto.OpResultCode_OPRC_RoomHadClosed
}
// 玩家已经在房间里了
if p.scene != nil {
logger.Logger.Warnf("(csm *CoinSceneMgr) PlayerEnter snid:%v find in gameId:%v gamefreeid:%v", p.SnId, p.scene.gameId, id)
return hall_proto.OpResultCode_OPRC_Error
}
csp := csm.GetCoinScenePool(platform.IdStr, id)
ret := csp.PlayerEnter(p, roomId, exclude, isChangeRoom)
logger.Logger.Warnf("(csm *CoinSceneMgr) PlayerEnter snid:%v find in id:%v exclude:%v return false", p.SnId, id, exclude)
return ret
}
// AudienceEnter 观众进入房间
func (csm *CoinSceneMgr) AudienceEnter(p *Player, id int32, roomId int32, exclude []int32, ischangeroom bool) hall_proto.OpResultCode {
//多平台支持
platform := p.GetPlatform()
if platform == nil {
return hall_proto.OpResultCode_OPRC_RoomHadClosed
}
pools, _, _ := csm.findCoinScenePool(platform.IdStr, id)
if pools == nil {
return hall_proto.OpResultCode_OPRC_RoomHadClosed
}
if len(pools) == 0 {
return hall_proto.OpResultCode_OPRC_NoFindDownTiceRoom
}
if csp, ok := pools[id]; ok && csp != nil {
ret := csp.AudienceEnter(p, roomId, exclude, ischangeroom)
logger.Logger.Warnf("(csm *CoinSceneMgr) AudienceEnter snid:%v find in id:%v exclude:%v return false", p.SnId, id, exclude)
return ret
}
logger.Logger.Warnf("(csm *CoinSceneMgr) AudienceEnter snid:%v find in id:%v exclude:%v csp.AudienceEnter return false", p.SnId, id, exclude)
return hall_proto.OpResultCode_OPRC_Error
}
func (csm *CoinSceneMgr) playerLeave(p *Player, reason int) bool {
if p == nil || p.scene == nil {
return true
}
s := p.scene
if s.groupId != 0 {
if ss, ok := csm.scenesOfGroup[s.groupId]; ok && ss != nil {
if csp, ok := ss[s.dbGameFree.GetId()]; ok && csp != nil {
if !csp.PlayerLeave(p, reason) {
csp.AudienceLeave(p, reason)
}
}
return true
}
}
// 玩家身上平台
if platform := p.GetPlatform(); platform != nil {
if ss, ok := csm.scenesOfPlatform[platform.IdStr]; ok && ss != nil {
if csp, ok := ss[s.dbGameFree.GetId()]; ok && csp != nil {
if !csp.PlayerLeave(p, reason) {
csp.AudienceLeave(p, reason)
}
}
return true
}
}
// 房间所在平台
if s.limitPlatform != nil {
if ss, ok := csm.scenesOfPlatform[s.limitPlatform.IdStr]; ok && ss != nil {
if csp, ok := ss[s.dbGameFree.GetId()]; ok && csp != nil {
if !csp.PlayerLeave(p, reason) {
csp.AudienceLeave(p, reason)
}
}
return true
}
}
return true
}
// PlayerLeave 玩家离开
func (csm *CoinSceneMgr) PlayerLeave(p *Player, reason int) bool {
logger.Logger.Tracef("玩家离开: snid %v, reason %v isAudience %v", p.SnId, reason)
return csm.playerLeave(p, reason)
}
// OnDestroyScene 解散房间
// sceneId 房间id
func (csm *CoinSceneMgr) OnDestroyScene(sceneId int) {
if platformName, ok := csm.platformOfScene[sceneId]; ok {
if ss, ok := csm.scenesOfPlatform[platformName]; ok {
for _, csp := range ss {
csp.OnDestroyScene(sceneId)
}
}
delete(csm.platformOfScene, sceneId)
}
if groupId, ok := csm.groupOfScene[sceneId]; ok {
if ss, ok := csm.scenesOfGroup[groupId]; ok {
for _, csp := range ss {
csp.OnDestroyScene(sceneId)
}
}
delete(csm.groupOfScene, sceneId)
}
}
// GetPlatformBySceneId 获取房间所在平台
func (csm *CoinSceneMgr) GetPlatformBySceneId(sceneId int) string {
if platformName, ok := csm.platformOfScene[sceneId]; ok {
return platformName
}
s := SceneMgrSingleton.GetScene(sceneId)
if s != nil && s.limitPlatform != nil {
return s.limitPlatform.IdStr
}
return DefaultPlatform
}
// GetPlayerNums 获取场次人数
func (csm *CoinSceneMgr) GetPlayerNums(p *Player, gameId, gameMode int32) []int32 {
//多平台支持
platform := p.GetPlatform()
var nums [10]int32
wantNum := [10]int32{80, 50, 30, 20, 10, 10, 10, 10, 10, 10}
for i := 0; i < 10; i++ {
if wantNum[i]/2 > 0 {
nums[i] = rand.Int31n(wantNum[i]/2) + wantNum[i]
}
}
if platform == nil {
return nums[:]
}
ids, _ := srvdata.GameFreeMgr.GetGameFreeIds(gameId, gameMode)
for _, id := range ids {
gps := PlatformMgrSingleton.GetGameFree(platform.IdStr, id)
if gps != nil {
if gps.GroupId != 0 {
if ss, exist := csm.scenesOfGroup[gps.GroupId]; exist {
if csp, exist := ss[id]; exist {
sceneType := csp.GetSceneType() - 1
if sceneType >= 0 && sceneType < len(nums) {
nums[sceneType] += csp.GetPlayerNum() + csp.GetFakePlayerNum()
}
}
}
} else {
if ss, ok := csm.scenesOfPlatform[platform.IdStr]; ok {
if csp, exist := ss[id]; exist {
sceneType := csp.GetSceneType() - 1
if sceneType >= 0 && sceneType < len(nums) {
nums[sceneType] += csp.GetPlayerNum() + csp.GetFakePlayerNum()
}
}
}
}
}
}
if len(ids) <= 10 {
return nums[:len(ids)]
}
return nums[:]
}
// InCoinScene 是否在场次中
func (csm *CoinSceneMgr) InCoinScene(p *Player) bool {
if p == nil {
logger.Logger.Tracef("(csm *CoinSceneMgr) InCoinScene p == nil snid:%v ", p.SnId)
return false
}
if p.scene == nil {
return false
}
if p.scene.csp == nil {
return false
}
return true
}
// PlayerTryLeave 通知游戏服务玩家要离开房间
func (csm *CoinSceneMgr) PlayerTryLeave(p *Player, isAudience bool) hall_proto.OpResultCode {
if !csm.InCoinScene(p) {
logger.Logger.Tracef("(csm *CoinSceneMgr) PlayerTryLeave !csm.InCoinScene(p) snid:%v ", p.SnId)
return hall_proto.OpResultCode_OPRC_Sucess
}
// 通知gamesrv
op := common.CoinSceneOp_Leave
if isAudience {
op = common.CoinSceneOp_AudienceLeave
}
pack := &hall_proto.CSCoinSceneOp{
Id: proto.Int32(p.scene.csp.id),
OpType: proto.Int32(op),
}
proto.SetDefaults(pack)
common.TransmitToServer(p.sid, int(hall_proto.CoinSceneGamePacketID_PACKET_CS_COINSCENE_OP), pack, p.scene.gameSess.Session)
logger.Logger.Tracef("(csm *CoinSceneMgr) PlayerTryLeave snid:%v id:%v", p.SnId, pack.GetId())
return hall_proto.OpResultCode_OPRC_OpYield
}
func (csm *CoinSceneMgr) PlayerInChanging(p *Player) bool {
_, exist := csm.playerChanging[p.SnId]
return exist
}
func (csm *CoinSceneMgr) ClearPlayerChanging(p *Player) {
delete(csm.playerChanging, p.SnId)
}
func (csm *CoinSceneMgr) PlayerTryChange(p *Player, id int32, exclude []int32, isAudience bool) hall_proto.OpResultCode {
if csm.InCoinScene(p) {
return csm.StartChangeCoinSceneTransact(p, id, exclude, isAudience)
}
if isAudience {
return csm.AudienceEnter(p, id, 0, exclude, true)
}
return csm.PlayerEnter(p, id, 0, exclude, true)
}
func (csm *CoinSceneMgr) StartChangeCoinSceneTransact(p *Player, id int32, exclude []int32, isAudience bool) hall_proto.OpResultCode {
if p == nil || p.scene == nil {
logger.Logger.Warnf("(csm *CoinSceneMgr) StartChangeCoinSceneTransact p == nil || p.scene == nil snid:%v id:%v", p.SnId, id)
return hall_proto.OpResultCode_OPRC_Error
}
tNow := time.Now()
if !p.lastChangeScene.IsZero() && tNow.Sub(p.lastChangeScene) < time.Second {
logger.Logger.Warnf("(csm *CoinSceneMgr) StartChangeCoinSceneTransact !p.lastChangeScene.IsZero() && tNow.Sub(p.lastChangeScene) < time.Second snid:%v id:%v", p.SnId, id)
return hall_proto.OpResultCode_OPRC_ChangeRoomTooOften
}
tnp := &transact.TransNodeParam{
Tt: common.TransType_CoinSceneChange,
Ot: transact.TransOwnerType(common.GetSelfSrvType()),
Oid: common.GetSelfSrvId(),
AreaID: common.GetSelfAreaId(),
}
ctx := &CoinSceneChangeCtx{
id: id,
isClub: false,
snid: p.SnId,
sceneId: int32(p.scene.sceneId),
exclude: exclude,
isAudience: isAudience,
}
tNode := transact.DTCModule.StartTrans(tnp, ctx, CoinSceneChangeTimeOut)
if tNode != nil {
tNode.Go(core.CoreObject())
csm.playerChanging[p.SnId] = id
p.lastChangeScene = tNow
return hall_proto.OpResultCode_OPRC_Sucess
}
logger.Logger.Warnf("(csm *CoinSceneMgr) StartChangeCoinSceneTransact tNode == nil snid:%v id:%v", p.SnId, id)
return hall_proto.OpResultCode_OPRC_Error
}
// TouchCreateRoom 触发预创建房间
// 1.模块启动后触发
// 2.游戏服建立连接后触发
// 3.房间解散后触发
// 4.场次配置更新后
func (csm *CoinSceneMgr) TouchCreateRoom(platform string, gameFreeId int32) {
gf := PlatformMgrSingleton.GetGameFree(platform, gameFreeId)
if gf.Status && gf.DbGameFree.GetCreateRoomNum() > 0 {
logger.Logger.Tracef("TouchCreateRoom platform:%v gameFreeId:%v", platform, gameFreeId)
csm.delayCache = append(csm.delayCache, &CreateRoomCache{
platformName: platform,
gameFreeId: gameFreeId,
})
}
}
func (csm *CoinSceneMgr) ModuleName() string {
return "CoinSceneMgr"
}
func (csm *CoinSceneMgr) Init() {
// 房间池初始化
for _, platform := range PlatformMgrSingleton.GetPlatforms() {
if platform.Isolated || platform.IdStr == "" {
for _, v := range srvdata.PBDB_GameFreeMgr.Datas.GetArr() {
gps := PlatformMgrSingleton.GetGameFree(platform.IdStr, v.GetId())
if gps != nil {
csm.GetCoinScenePool(platform.IdStr, v.GetId())
csm.TouchCreateRoom(platform.IdStr, v.GetId())
}
}
}
}
}
func (csm *CoinSceneMgr) Update() {
cnt := len(csm.delayCache)
if cnt > 0 {
data := csm.delayCache[cnt-1]
csm.delayCache = csm.delayCache[:cnt-1]
gf := PlatformMgrSingleton.GetGameFree(data.platformName, data.gameFreeId)
if gf != nil && gf.DbGameFree != nil {
csp := csm.GetCoinScenePool(data.platformName, data.gameFreeId)
if csp != nil {
csp.PreCreateRoom()
}
}
}
}
func (csm *CoinSceneMgr) Shutdown() {
module.UnregisteModule(csm)
}
//=====================PlatformObserver======================
func (this *CoinSceneMgr) OnPlatformCreate(p *Platform) {
}
func (this *CoinSceneMgr) OnPlatformDestroy(p *Platform) {
if p == nil {
return
}
var ids []int
if v, ok := this.scenesOfPlatform[p.IdStr]; ok {
for _, csp := range v {
for _, scene := range csp.scenes {
ids = append(ids, scene.sceneId)
}
}
}
SceneMgrSingleton.DoDelete(ids, true)
}
func (this *CoinSceneMgr) OnPlatformChangeDisabled(p *Platform, disabled bool) {
if disabled {
this.OnPlatformDestroy(p)
}
}
func (this *CoinSceneMgr) OnPlatformGameFreeUpdate(p *Platform, oldCfg, newCfg *webapi.GameFree) {
if p == nil || newCfg == nil {
return
}
var ss map[int32]*CoinScenePool
var ok bool
if oldCfg.GroupId != newCfg.GroupId || oldCfg.GroupId != 0 {
ss, ok = this.scenesOfGroup[oldCfg.GroupId]
} else {
ss, ok = this.scenesOfPlatform[p.IdStr]
}
if !ok || ss == nil {
return
}
if cps, ok := ss[newCfg.DbGameFree.Id]; ok {
cps.dbGameFree = newCfg.DbGameFree
var ids []int
for _, scene := range cps.scenes {
ids = append(ids, scene.sceneId)
}
SceneMgrSingleton.DoDelete(ids, true)
this.TouchCreateRoom(p.IdStr, newCfg.DbGameFree.Id)
}
}
func (this *CoinSceneMgr) OnPlatformDestroyByGameFreeId(p *Platform, gameFreeId int32) {
if p == nil {
return
}
if csps, ok := this.scenesOfPlatform[p.IdStr]; ok {
var ids []int
for _, csp := range csps {
for _, scene := range csp.scenes {
if scene.dbGameFree.Id == gameFreeId {
ids = append(ids, scene.sceneId)
}
}
}
SceneMgrSingleton.DoDelete(ids, true)
}
}
//=========================PlatformGameGroupObserver==============================
func (this *CoinSceneMgr) OnGameGroupUpdate(oldCfg, newCfg *webapi.GameConfigGroup) {
if newCfg == nil {
return
}
if scenes, exist := this.scenesOfGroup[newCfg.Id]; exist {
if cps, ok := scenes[newCfg.DbGameFree.Id]; ok {
needDestroy := false
if cps.dbGameFree.GetBot() != newCfg.DbGameFree.GetBot() ||
cps.dbGameFree.GetBaseScore() != newCfg.DbGameFree.GetBaseScore() ||
cps.dbGameFree.GetLimitCoin() != newCfg.DbGameFree.GetLimitCoin() ||
cps.dbGameFree.GetMaxCoinLimit() != newCfg.DbGameFree.GetMaxCoinLimit() ||
cps.dbGameFree.GetTaxRate() != newCfg.DbGameFree.GetTaxRate() ||
!common.SliceInt64Equal(cps.dbGameFree.GetOtherIntParams(), newCfg.DbGameFree.GetOtherIntParams()) ||
!common.SliceInt64Equal(cps.dbGameFree.GetRobotTakeCoin(), newCfg.DbGameFree.GetRobotTakeCoin()) ||
!common.SliceInt64Equal(cps.dbGameFree.GetRobotLimitCoin(), newCfg.DbGameFree.GetRobotLimitCoin()) {
needDestroy = true
}
//TODO 预创建房间配置更新,unsupport group model
cps.dbGameFree = newCfg.DbGameFree
if needDestroy {
var ids []int
for _, scene := range cps.scenes {
ids = append(ids, scene.sceneId)
}
SceneMgrSingleton.DoDelete(ids, true)
}
}
}
}
//=========================GameSessionListener======================================
func (csm *CoinSceneMgr) OnGameSessionRegiste(gs *GameSession) {
wildGs := len(gs.gameIds) == 0 || common.InSliceInt32(gs.gameIds, 0) // 是否所有游戏都支持
for _, platform := range PlatformMgrSingleton.GetPlatforms() {
if platform.IdStr == DefaultPlatform {
continue
}
//获取配置
gps := PlatformMgrSingleton.GetGameFrees(platform.IdStr)
for _, v := range gps {
if v != nil && (wildGs || common.InSliceInt32(gs.gameIds, v.DbGameFree.GetGameId())) {
csm.TouchCreateRoom(platform.IdStr, v.DbGameFree.Id)
}
}
}
}
func (this *CoinSceneMgr) OnGameSessionUnregiste(gs *GameSession) {
//todo 游戏服务断开,是否解散房间?
}
func init() {
module.RegisteModule(CoinSceneMgrSingleton, time.Second*2, 0)
PlatformMgrSingleton.RegisterObserver(CoinSceneMgrSingleton)
PlatformGameGroupMgrSington.RegisteObserver(CoinSceneMgrSingleton)
RegisteGameSessionListener(CoinSceneMgrSingleton)
}