package chesstitians import ( "math/rand" "time" "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/logger" "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/chess" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/chesstitians" ) var ScenePolicyEntitySingleton = &ScenePolicyEntity{} type ScenePolicyEntity struct { base.BaseScenePolicy states [rule.SceneStateMax]base.SceneState } // 创建场景扩展数据 func (this *ScenePolicyEntity) CreateSceneExData(s *base.Scene) interface{} { sceneEx := NewSceneEx(s) if sceneEx != nil { if sceneEx.init() { sceneEx.Clear() s.SetExtraData(sceneEx) } } return sceneEx } // 创建玩家扩展数据 func (this *ScenePolicyEntity) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { playerEx := &PlayerEx{Player: p} if playerEx != nil { playerEx.init() p.SetExtraData(playerEx) } return playerEx } // 场景开启事件 func (this *ScenePolicyEntity) OnStart(s *base.Scene) { logger.Logger.Trace("(this *ScenePolicyEntity) OnStart, GetSceneId()=", s.GetSceneId()) sceneEx := NewSceneEx(s) if sceneEx != nil { if sceneEx.init() { sceneEx.Clear() s.SetExtraData(sceneEx) s.ChangeSceneState(rule.SceneStateWaitPlayer) } } } // 场景心跳事件 func (this *ScenePolicyEntity) OnTick(s *base.Scene) { if s == nil { return } if s.GetSceneState() != nil { s.GetSceneState().OnTick(s) } } // 玩家进入事件 func (this *ScenePolicyEntity) OnPlayerEnter(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerEnter, GetSceneId()=", s.GetSceneId(), " player=", p.GetName()) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { //自动带入金币 pos := sceneEx.FindOnePos() if p.Pos != rule.InvalidPos && sceneEx.seats[p.Pos] == nil { pos = p.Pos } if pos < 0 || pos > 1 || sceneEx.seats[pos] != nil { p.MarkFlag(base.PlayerState_EnterSceneFailed) cnt := len(sceneEx.players) logger.Logger.Warnf("ScenePolicyEntity.OnPlayerEnter(scene:%v, player:%v) no found fit GetPos(), current player count:%v NumOfGames:%v", s.GetSceneId(), p.SnId, cnt, sceneEx.NumOfGames) return } playerEx := &PlayerEx{Player: p} playerEx.init() playerEx.SetPos(pos) if sceneEx.GetGaming() { playerEx.MarkFlag(base.PlayerState_WaitNext) } p.SetExtraData(playerEx) sceneEx.seats[pos] = playerEx sceneEx.players[p.SnId] = playerEx if sceneEx.GetSeatPlayerCnt() == 1 { sceneEx.masterSnId = playerEx.SnId sceneEx.BroadcastUpdateMasterSnId(false) } //广播个人信息 playerData := CreatePlayerData(p) if sceneEx.IsMatchScene() && p.IsRob { if len(p.MatchParams) > 2 { if p.MatchParams[2] != 0 { playerData.CopySnid = p.MatchParams[2] } } if len(p.MatchParams) > 3 { if p.MatchParams[3] != 0 { playerData.CopyRoleId = p.MatchParams[3] } } } pack := &chesstitians.SCChesstitiansPlayerEnter{ Data: playerData, } proto.SetDefaults(pack) s.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansPlayerEnter), pack, p.GetSid()) //给自己发送房间信息 SendRoomInfo(s, p, sceneEx, playerEx) s.FirePlayerEvent(p, base.PlayerEventEnter, nil) } } // 玩家离开事件 func (this *ScenePolicyEntity) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerLeave, GetSceneId()=", s.GetSceneId(), " player=", p.SnId) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if playerEx, ok := p.GetExtraData().(*PlayerEx); ok { if this.CanChangeCoinScene(s, p) { LeavePlayerSnid := playerEx.SnId sceneEx.OnPlayerLeave(p, reason) s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) if LeavePlayerSnid == sceneEx.masterSnId { findOne := false for i := 0; i < sceneEx.GetPlayerNum(); i++ { playerExSeat := sceneEx.seats[i] if playerExSeat != nil && playerExSeat.SnId != sceneEx.masterSnId { sceneEx.masterSnId = playerExSeat.SnId sceneEx.BroadcastUpdateMasterSnId(true) findOne = true break } } if !findOne { sceneEx.masterSnId = 0 sceneEx.BroadcastUpdateMasterSnId(false) } } if !playerEx.IsRob { //真人离开 hadSeat := false for _, seat := range sceneEx.seats { if seat != nil { hadSeat = true break } } if !hadSeat { //座位上没有人了,把观众踢出去 audiences := sceneEx.GetAudiences() for _, audience := range audiences { if audience != nil { s.AudienceLeave(audience, common.PlayerLeaveReason_RoomClose) } } } } } } } } // 玩家掉线 func (this *ScenePolicyEntity) OnPlayerDropLine(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerDropLine, GetSceneId()=", s.GetSceneId(), " player=", p.Name) s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if sceneEx.GetGaming() { if s.IsMatchScene() || s.IsCoinScene() { p.MarkFlag(base.PlayerState_Auto) p.SyncFlag() } return } s.PlayerLeave(p, common.PlayerLeaveReason_DropLine, true) } } // 玩家重连 func (this *ScenePolicyEntity) OnPlayerRehold(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerRehold, GetSceneId()=", s.GetSceneId(), " player=", p.Name) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if playerEx, ok := p.GetExtraData().(*PlayerEx); ok { if p.IsMarkFlag(base.PlayerState_Auto) { p.UnmarkFlag(base.PlayerState_Auto) p.SyncFlag() } //发送房间信息给自己 SendRoomInfo(s, p, sceneEx, playerEx) s.FirePlayerEvent(p, base.PlayerEventRehold, nil) } } } // 返回房间 func (this *ScenePolicyEntity) OnPlayerReturn(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerReturn, GetSceneId()=", s.GetSceneId(), " player=", p.Name) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if playerEx, ok := p.GetExtraData().(*PlayerEx); ok { if p.IsMarkFlag(base.PlayerState_Auto) { p.UnmarkFlag(base.PlayerState_Auto) p.SyncFlag() } //发送房间信息给自己 SendRoomInfo(s, p, sceneEx, playerEx) s.FirePlayerEvent(p, base.PlayerEventReturn, nil) } } } func (this *ScenePolicyEntity) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if s == nil || p == nil { return false } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerOp, GetSceneId()=", s.GetSceneId(), " player=", p.GetName(), " opcode=", opcode, " params=", params) if s.GetSceneState() != nil { if s.GetSceneState().OnPlayerOp(s, p, opcode, params) { p.LastOPTimer = time.Now() return true } return false } return true } func (this *ScenePolicyEntity) OnPlayerDevOp(s *base.Scene, p *base.Player, opcode int, paramStr []string, param int64) bool { if s == nil || p == nil { return false } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerDevOp, GetSceneId()=", s.GetSceneId(), " player=", p.GetName(), " opcode=", opcode, " paramsStr=", paramStr, " param=", param) sceneEx, _ := s.GetExtraData().(*SceneEx) sceneEx.chess.SetChess(paramStr) //sceneEx.opPos = int32(param) snid := int32(param) for idx, seat := range sceneEx.seats { if seat.GetSnId() == snid { sceneEx.opPos = idx break } } sceneEx.lastMove = []int32{} //playerEx, _ := p.GetExtraData().(*PlayerEx) //pack := CreateRoomInfoPacket(s, p, sceneEx, playerEx) //s.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansRoomInfo), pack, 0) for _, seat := range sceneEx.seats { if seat != nil { pack := CreateRoomInfoPacket(s, seat.Player, sceneEx, seat) ok := seat.Player.SendToClient(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansRoomInfo), pack) logger.Logger.Trace("SCChesstitiansSendRoomInfo isok : ", ok, ",pack", pack) } } return true } func (this *ScenePolicyEntity) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyEntity) OnPlayerEvent, GetSceneId()=", s.GetSceneId(), " player=", p.GetName(), " eventcode=", evtcode, " params=", params) if s.GetSceneState() != nil { s.GetSceneState().OnPlayerEvent(s, p, evtcode, params) } } func (this *ScenePolicyEntity) OnAudienceEnter(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("ScenePolicyEntity OnAudienceEnter, sceneId=", s.SceneId, " player=", p.SnId) this.BaseScenePolicy.OnAudienceEnter(s, p) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { //给自己发送房间信息 p.UnmarkFlag(base.PlayerState_Leave) SendRoomInfo(s, p, sceneEx, nil) sceneEx.BroadcastAudienceNum(p) } } func (this *ScenePolicyEntity) OnAudienceLeave(s *base.Scene, p *base.Player, reason int) { if s == nil || p == nil { return } logger.Logger.Trace("ScenePolicyEntity OnAudienceLeave, sceneId=", s.SceneId, " player=", p.SnId, " reason=", reason) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { sceneEx.BroadcastAudienceNum(p) } } func (this *ScenePolicyEntity) OnAudienceSit(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("ScenePolicyEntity OnAudienceSit, sceneId=", s.SceneId, " player=", p.SnId) sceneEx, ok := s.GetExtraData().(*SceneEx) if !ok { return } if s.Gaming && !s.GetBEnterAfterStart() { return } //自动带入金币 pos := sceneEx.FindOnePos() if pos < 0 || pos > 3 || sceneEx.seats[pos] != nil { p.MarkFlag(base.PlayerState_EnterSceneFailed) cnt := len(sceneEx.players) logger.Logger.Warnf("ScenePolicyEntity.OnAudienceSit(scene:%v, player:%v) no found fit GetPos(), current player count:%v NumOfGames:%v", s.GetSceneId(), p.SnId, cnt, sceneEx.NumOfGames) return } playerEx := &PlayerEx{Player: p} playerEx.init() playerEx.SetPos(pos) p.UnmarkFlag(base.PlayerState_Audience) p.UnmarkFlag(base.PlayerState_Leave) if sceneEx.GetGaming() { playerEx.MarkFlag(base.PlayerState_WaitNext) p.SyncFlag() } p.SetExtraData(playerEx) sceneEx.seats[pos] = playerEx sceneEx.players[p.SnId] = playerEx //logger.Logger.Trace("广播个人信息,curSeatsNum: ", sceneEx.GetSeatPlayerCnt()) if sceneEx.GetSeatPlayerCnt() == 1 { sceneEx.masterSnId = playerEx.SnId sceneEx.BroadcastUpdateMasterSnId(false) } //广播个人信息 playerData := CreatePlayerData(p) pack := &chesstitians.SCChesstitiansPlayerEnter{ Data: playerData, } proto.SetDefaults(pack) s.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansPlayerEnter), pack, p.GetSid()) //给自己发送房间信息 SendRoomInfo(s, p, sceneEx, playerEx) sceneEx.BroadcastAudienceNum(p) s.FirePlayerEvent(p, base.PlayerEventEnter, nil) } func (this *ScenePolicyEntity) OnAudienceDropLine(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("ScenePolicyEntity OnAudienceDropLine, sceneId=", s.SceneId, " player=", p.SnId) s.AudienceLeave(p, common.PlayerLeaveReason_DropLine) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { sceneEx.BroadcastAudienceNum(p) } } // 是否完成了整个牌局 func (this *ScenePolicyEntity) IsCompleted(s *base.Scene) bool { if s == nil { return false } return false } // 是否可以强制开始 func (this *ScenePolicyEntity) IsCanForceStart(s *base.Scene) bool { return false } // 当前状态能否换桌 func (this *ScenePolicyEntity) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { if s == nil || p == nil { return false } if s.GetSceneState() != nil { return s.GetSceneState().CanChangeCoinScene(s, p) } return true } func (this *ScenePolicyEntity) ForceStart(s *base.Scene) { s.ChangeSceneState(rule.SceneStateWaitStart) } func CreatePlayerData(p *base.Player) *chesstitians.ChesstitiansPlayerData { pd := &chesstitians.ChesstitiansPlayerData{ Name: proto.String(p.Name), SnId: proto.Int32(p.SnId), Head: proto.Int32(p.Head), Sex: proto.Int32(p.Sex), Coin: proto.Int64(p.GetCoin()), Flag: proto.Int(p.GetFlag()), Longitude: proto.Int32(p.Longitude), Latitude: proto.Int32(p.Latitude), City: proto.String(p.City), VIP: proto.Int32(p.VIP), HeadOutLine: proto.Int32(p.HeadOutLine), NiceId: proto.Int32(p.NiceId), Pos: proto.Int(p.GetPos()), ChessGrade: proto.Int64(p.ChessGrade), IsRob: proto.Bool(p.IsRob), Level: proto.Int64(p.Level), Exp: proto.Int64(p.Exp), } ex, ok := p.GetExtraData().(*PlayerEx) if ok { pd.IsWin = ex.isWin pd.WinTimes = ex.winTimes pd.OtherScore = ex.otherScore pd.NextRank = ex.nextRank pd.WinScore = ex.winScore pd.WinCoin = ex.winCoin pd.OldChessGrade = ex.oldGrade pd.TotalTime = ex.GetTotalTime() } if p.Roles != nil { pd.RoleId = proto.Int32(p.Roles.ModId) } if p.Items != nil { pd.Items = make(map[int32]int32) for id, num := range p.Items { pd.Items[id] = int32(num) } } if len(p.MatchParams) > 0 { pd.MatchRankId = p.MatchParams[0] } if len(p.MatchParams) > 1 { pd.Lv = p.MatchParams[1] } logger.Logger.Trace("ChesstitiansCreatePlayerData pd : ", pd) return pd } func CreateRoomInfoPacket(s *base.Scene, p *base.Player, sceneEx *SceneEx, playerEx *PlayerEx) *chesstitians.SCChesstitiansRoomInfo { pack := &chesstitians.SCChesstitiansRoomInfo{ RoomId: proto.Int(s.GetSceneId()), Creator: proto.Int32(s.GetCreator()), GameId: proto.Int(s.GetGameId()), RoomMode: proto.Int(s.GetSceneMode()), Params: common.CopySliceInt64ToInt32(s.GetParams()), State: proto.Int32(int32(s.GetSceneState().GetState())), TimeOut: proto.Int(s.GetSceneState().GetTimeout(s)), NumOfGames: proto.Int(sceneEx.NumOfGames), TotalOfGames: sceneEx.TotalOfGames, CurOpIdx: proto.Int(-1), MasterSnid: proto.Int32(sceneEx.masterSnId), AudienceNum: proto.Int(s.GetAudiencesNum()), BaseScore: proto.Int32(s.BaseScore), MaxPlayerNum: proto.Int(s.GetPlayerNum()), GameFreeId: proto.Int32(s.GetDBGameFree().GetId()), SceneType: proto.Int32(s.GetDBGameFree().GetSceneType()), // 计步 StepSnId: proto.Int32(sceneEx.stepSnId), StepNum: int64(sceneEx.stepNum), StepLimit: int64(sceneEx.stepLimit), // 求和 DrawSnId: proto.Int32(sceneEx.drawSnId), // 发起再来一局的玩家 NextSnId: proto.Int32(sceneEx.nextSnId), } pack.Variant = int32(sceneEx.chess.GetVariant()) // 生成棋数据 pack.Chess = sceneEx.chess.GetChess() pack.Act = sceneEx.chess.GetAct() pack.Castling = sceneEx.chess.GetCastling() pack.CambodianMove = sceneEx.chess.GetCambodianMove() pack.Enpassant = int32(sceneEx.chess.GetEnPassant()) pack.ChessRound = int32(sceneEx.chess.GetRound()) pack.Check = sceneEx.chess.GetCheck() pack.Checkmate = sceneEx.chess.GetCheckmate() for _, v := range sceneEx.lastMove { pack.LastMove = append(pack.LastMove, int32(v)) } pack.IsMatch = int32(0) // 0.普通场 1.锦标赛 2.冠军赛 3.vip专属 if s.IsMatchScene() { } pack.MatchFinals = 0 if s.GetMatch().GetIsFinals() { pack.MatchFinals = 1 if s.NumOfGames >= 2 { pack.MatchFinals = 2 } } if s.GetSceneState().GetState() == rule.SceneStateBilled { sceneEx.opPos = -1 pack.CurOpIdx = proto.Int32(-1) } if s.GetSceneState().GetState() >= rule.SceneStatePlayerOp { pack.CurOpIdx = proto.Int32(int32(sceneEx.opPos)) } //玩家信息.第一个必然是自己 pd := CreatePlayerData(p) if playerEx != nil { // 是黑棋的标记?1黑棋,0白棋 if playerEx.isBlack { pd.IsBlack = proto.Int32(1) } else { pd.IsBlack = proto.Int32(0) } } pack.Players = append(pack.Players, pd) //剩下的按座位排序 for i := 0; i < sceneEx.GetPlayerNum(); i++ { nowPlayer := sceneEx.seats[i] if nowPlayer != nil { if nowPlayer.SnId != p.SnId { pd1 := CreatePlayerData(nowPlayer.Player) if sceneEx.IsMatchScene() && nowPlayer.IsRob { if len(nowPlayer.MatchParams) > 2 { if nowPlayer.MatchParams[2] != 0 { pd1.CopySnid = nowPlayer.MatchParams[2] } } if len(nowPlayer.MatchParams) > 3 { if nowPlayer.MatchParams[3] != 0 { pd1.CopyRoleId = nowPlayer.MatchParams[3] } } } // 是黑棋的标记?1黑棋,0白棋 if nowPlayer.isBlack { pd1.IsBlack = proto.Int32(1) } else { pd1.IsBlack = proto.Int32(0) } pack.Players = append(pack.Players, pd1) } } } proto.SetDefaults(pack) return pack } func SendRoomInfo(s *base.Scene, p *base.Player, sceneEx *SceneEx, playerEx *PlayerEx) { pack := CreateRoomInfoPacket(s, p, sceneEx, playerEx) ok := p.SendToClient(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansRoomInfo), pack) logger.Logger.Trace("SCChesstitiansSendRoomInfo isok : ", ok, ",pack", pack) } //===================================== // SceneStateBase 状态基类 //===================================== type SceneStateBase struct { } func (this *SceneStateBase) GetTimeout(s *base.Scene) int { if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { return int(time.Now().Sub(sceneEx.StateStartTime) / time.Second) } return 0 } func (this *SceneStateBase) CanChangeTo(s base.SceneState) bool { return true } func (this *SceneStateBase) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { return !p.IsGameing() || s.GetDestroyed() } func (this *SceneStateBase) OnEnter(s *base.Scene) { if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { sceneEx.StateStartTime = time.Now() } } func (this *SceneStateBase) OnLeave(s *base.Scene) {} func (this *SceneStateBase) OnTick(s *base.Scene) { } func (this *SceneStateBase) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { logger.Logger.Trace("SceneBaseStateChesstitians.", " s.GetSceneId() : ", s.GetSceneId(), " p.SnId : ", p.SnId, " opcode : ", opcode, " params ", params) sceneEx, _ := s.GetExtraData().(*SceneEx) if sceneEx == nil { return true } playerEx, _ := p.GetExtraData().(*PlayerEx) if playerEx == nil { return true } return false } func (this *SceneStateBase) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { } // BroadcastRoomState 广播房间状态 func (this *SceneStateBase) BroadcastRoomState(s *base.Scene, state int, params ...int64) { pack := &chesstitians.SCChesstitiansRoomState{ State: proto.Int(state), Params: params, } proto.SetDefaults(pack) s.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansRoomState), pack, 0) } //===================================== // SceneStateWaitPlayer 等待玩家进入 //===================================== type SceneStateWaitPlayer struct { SceneStateBase } func (this *SceneStateWaitPlayer) GetState() int { return rule.SceneStateWaitPlayer } func (this *SceneStateWaitPlayer) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.SceneStateWaitStart: return true default: return false } } func (this *SceneStateWaitPlayer) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { if s.IsMatchScene() { return false } return true } func (this *SceneStateWaitPlayer) OnEnter(s *base.Scene) { this.SceneStateBase.OnEnter(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { sceneEx.Clear() sceneEx.SetGaming(false) this.BroadcastRoomState(s, this.GetState()) } } // 状态离开时 func (this *SceneStateWaitPlayer) OnLeave(s *base.Scene) { this.SceneStateBase.OnLeave(s) logger.Logger.Tracef("(this *SceneWaitPlayerStateChesstitians) OnLeave, sceneid=%v", s.GetSceneId()) } // 玩家操作 func (this *SceneStateWaitPlayer) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.SceneStateBase.OnPlayerOp(s, p, opcode, params) { return true } return true } // 玩家事件 func (this *SceneStateWaitPlayer) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *SceneWaitPlayerStateChesstitians) OnPlayerEvent, GetSceneId()=", s.GetSceneId(), " player=", p.Name, " evtcode=", evtcode) this.SceneStateBase.OnPlayerEvent(s, p, evtcode, params) if _, ok := p.GetExtraData().(*PlayerEx); ok { if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { switch evtcode { case base.PlayerEventEnter: // 段位等级没有设置不能玩游戏,不应该有这个错误的 if len(sceneEx.ChessRank) == 0 && s.GetGameId() != common.GameId_ChesstitiansCambodianRobot { logger.Logger.Errorf("ChessRank not found Platform:%v", sceneEx.Platform) sceneEx.SceneDestroy(true) return } //如果有人进入, 检查在线人是否能够开启游戏,够的话,切换到延迟开启状态 if sceneEx.CanStart() { logger.Logger.Tracef("(this *SceneWaitPlayerStateChesstitians) OnPlayerEvent s.ChangeSceneState(SceneStateWaitStart) %v", s.GetSceneId()) s.ChangeSceneState(rule.SceneStateWaitStart) } } } } } func (this *SceneStateWaitPlayer) OnTick(s *base.Scene) { this.SceneStateBase.OnTick(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if s.CheckNeedDestroy() { sceneEx.SceneDestroy(true) return } if sceneEx.CanStart() { logger.Logger.Tracef("(this *SceneWaitPlayerStateChesstitians) OnTick s.ChangeSceneState(SceneStateWaitStart) %v", s.GetSceneId()) s.ChangeSceneState(rule.SceneStateWaitStart) } else if !s.GetGaming() && s.GetRobotNum() == 1 { tNow := time.Now() for _, p := range s.Players { if p.IsRob && tNow.Sub(p.GetLastOPTimer()) > time.Second*time.Duration(30+rand.Int63n(60)) { //p.LastOPTimer = tNow.Add(time.Minute * 30) s.PlayerLeave(p, common.PlayerLeaveReason_Normal, true) } } } } } //===================================== // SceneStateWaitStart 开始游戏 //===================================== type SceneStateWaitStart struct { SceneStateBase } func (this *SceneStateWaitStart) GetState() int { return rule.SceneStateWaitStart } func (this *SceneStateWaitStart) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.SceneStateWaitPlayer, rule.SceneStateWaitStart, rule.SceneStateChessInit: return true default: return false } } // 当前状态能否换桌 func (this *SceneStateWaitStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { if s.IsMatchScene() { return false } return true } func (this *SceneStateWaitStart) OnEnter(s *base.Scene) { this.SceneStateBase.OnEnter(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { sceneEx.Clear() sceneEx.SetGaming(false) this.BroadcastRoomState(s, this.GetState()) logger.Logger.Trace("(this *SceneWaitStartStateChesstitians) OnEnter", this.GetState()) } } // 状态离开时 func (this *SceneStateWaitStart) OnLeave(s *base.Scene) { this.SceneStateBase.OnLeave(s) logger.Logger.Tracef("(this *SceneWaitStartStateChesstitians) OnLeave", this.GetState()) } // 玩家操作 func (this *SceneStateWaitStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.SceneStateBase.OnPlayerOp(s, p, opcode, params) { return true } sceneEx, _ := s.GetExtraData().(*SceneEx) if sceneEx != nil { playerEx, _ := p.GetExtraData().(*PlayerEx) if playerEx != nil { opRetCode := chesstitians.OpResultCode_OPRC_Error if playerEx.SnId == sceneEx.masterSnId && this.GetState() == rule.SceneStateWaitStart { if sceneEx.IsMatchScene() { return false } switch int32(opcode) { case rule.PlayerOpStart: //房主开始游戏 if sceneEx.CanStart() == false { s.ChangeSceneState(rule.SceneStateWaitPlayer) } else { opRetCode = chesstitians.OpResultCode_OPRC_Sucess s.ChangeSceneState(rule.SceneStateChessInit) } } } if opRetCode == chesstitians.OpResultCode_OPRC_Sucess { sceneEx.OnPlayerSCOp(p, opcode, opRetCode, params) } else { logger.Logger.Tracef("SceneWaitStartStateChesstitians OnPlayerOp snid:%v, masterSnId:%v", playerEx.SnId, sceneEx.masterSnId) } } } return true } // 玩家事件 func (this *SceneStateWaitStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *SceneWaitStartStateChesstitians) OnPlayerEvent, GetSceneId()=", s.GetSceneId(), " player=", p.Name, " evtcode=", evtcode) this.SceneStateBase.OnPlayerEvent(s, p, evtcode, params) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { switch evtcode { case base.PlayerEventLeave: //如果有人退出, 检查在线人是否能够开启游戏,不够的话,切换到等待状态 if !sceneEx.CanStart() { s.ChangeSceneState(rule.SceneStateWaitPlayer) } } } } func (this *SceneStateWaitStart) OnTick(s *base.Scene) { this.SceneStateBase.OnTick(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if sceneEx.IsMatchScene() { delayT := time.Second * 2 if sceneEx.GetMatch().GetCurrRound() != 1 { //第一轮延迟2s,其他延迟3s 配合客户端播放动画 delayT = time.Second * 4 } if time.Now().Sub(sceneEx.StateStartTime) > delayT { s.ChangeSceneState(rule.SceneStateChessInit) // 比赛场直接发牌 return } } if time.Now().Sub(sceneEx.StateStartTime) > rule.WaitStartTimeout { //开始前再次检查开始条件 if sceneEx.CanStart() { s.ChangeSceneState(rule.SceneStateChessInit) } else { s.ChangeSceneState(rule.SceneStateWaitPlayer) } } } } //===================================== // SceneStateChessInit 棋盘初始化 //===================================== type SceneStateChessInit struct { SceneStateBase } func (this *SceneStateChessInit) GetState() int { return rule.SceneStateChessInit } func (this *SceneStateChessInit) CanChangeTo(s base.SceneState) bool { if s.GetState() == rule.SceneStatePlayerOp { return true } return false } func (this *SceneStateChessInit) OnEnter(s *base.Scene) { this.SceneStateBase.OnEnter(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { sceneEx.Clear() sceneEx.SetGaming(true) sceneEx.GameNowTime = time.Now() sceneEx.AllPlayerEnterGame() //参与游戏次数 for i := 0; i < sceneEx.GetPlayerNum(); i++ { playerEx := sceneEx.seats[i] if playerEx != nil { if playerEx.IsGameing() { playerEx.GameTimes++ } } } s.NumOfGames++ s.NotifySceneRoundStart(s.NumOfGames) this.BroadcastRoomState(s, this.GetState(), int64(s.NumOfGames)) //发牌 sceneEx.ChessInit() } } // 状态离开时 func (this *SceneStateChessInit) OnLeave(s *base.Scene) { this.SceneStateBase.OnLeave(s) logger.Logger.Tracef("(this *SceneHandCardStateChesstitians) OnLeave, sceneid=%v", s.GetSceneId()) } // 玩家操作 func (this *SceneStateChessInit) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.SceneStateBase.OnPlayerOp(s, p, opcode, params) { return true } return true } // 玩家事件 func (this *SceneStateChessInit) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *SceneHandCardStateChesstitians) OnPlayerEvent, GetSceneId()=", s.GetSceneId(), " player=", p.Name, " evtcode=", evtcode) this.SceneStateBase.OnPlayerEvent(s, p, evtcode, params) } func (this *SceneStateChessInit) OnTick(s *base.Scene) { this.SceneStateBase.OnTick(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { if time.Now().Sub(sceneEx.StateStartTime) > rule.HandCardTimeout { for i := 0; i < sceneEx.GetPlayerNum(); i++ { seat := sceneEx.seats[i] if !seat.isBlack { sceneEx.SetCurOpPos(seat.GetPos()) } } s.ChangeSceneState(rule.SceneStatePlayerOp) } } } //===================================== // SceneStatePlayerOp 玩家操作状态 //===================================== type SceneStatePlayerOp struct { SceneStateBase } func (this *SceneStatePlayerOp) GetState() int { return rule.SceneStatePlayerOp } func (this *SceneStatePlayerOp) CanChangeTo(s base.SceneState) bool { if s.GetState() == rule.SceneStateBilled { return true } return false } func (this *SceneStatePlayerOp) OnEnter(s *base.Scene) { this.SceneStateBase.OnEnter(s) this.BroadcastRoomState(s, this.GetState()) } // 状态离开时 func (this *SceneStatePlayerOp) OnLeave(s *base.Scene) { this.SceneStateBase.OnLeave(s) logger.Logger.Tracef("(this *SceneHandCardStateChesstitians) OnLeave, sceneid=%v", s.GetSceneId()) } // 玩家操作 func (this *SceneStatePlayerOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.SceneStateBase.OnPlayerOp(s, p, opcode, params) { return true } this.OnPlayerOpNormal(s, p, opcode, params) this.OnPlayerOpAI(s, p, opcode, params) return true } func (this *SceneStatePlayerOp) OnPlayerOpNormal(s *base.Scene, p *base.Player, opcode int, params []int64) bool { sceneEx, ok := s.GetExtraData().(*SceneEx) if !ok { return true } if sceneEx == nil { return true } playerEx, ok := p.GetExtraData().(*PlayerEx) if !ok { return true } if playerEx == nil { return true } returnFunc := func(code chesstitians.OpResultCode) { if code == chesstitians.OpResultCode_OPRC_Sucess { // 可以成功行棋,则同步给所有的玩家 sceneEx.BroadcastPlayerSCOp(playerEx.SnId, opcode, code, params) if sceneEx.winSnId != 0 { sceneEx.ChangeSceneState(rule.SceneStateBilled) } } else { // 若不能成功操作,仅发给操作的玩家 sceneEx.OnPlayerSCOp(p, opcode, code, params) } } switch int32(opcode) { case rule.PlayerOpPlay: // 玩家行棋 if sceneEx.GetCurOpPos() != playerEx.GetPos() { return false } if len(params) != 2 { returnFunc(chesstitians.OpResultCode_OPRC_Error) return true } if sceneEx.PlayChess(params) { // 轮换当前操作标记 sceneEx.NextOpPos() sceneEx.StateStartTime = time.Now() returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true case rule.PlayerOpSurrender: // 投降 for _, seat := range sceneEx.seats { if seat != nil { if seat.GetSnId() != playerEx.GetSnId() { sceneEx.winSnId = seat.GetSnId() break } } } returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true case rule.PlayerOpDraw: // 求和 if len(params) == 0 { returnFunc(chesstitians.OpResultCode_OPRC_Error) return true } switch params[0] { case rule.RequestDraw: if sceneEx.RequestDraw(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true case rule.CancelDraw: if sceneEx.CancelDraw(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true case rule.RefuseDraw: if sceneEx.RefuseDraw(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true case rule.AgreeDraw: if sceneEx.AgreeDraw(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true } case rule.PlayerOpStep: // 计步操作 // 参数校验 if len(params) == 0 { returnFunc(chesstitians.OpResultCode_OPRC_Error) return true } switch params[0] { case rule.StepStart: // 开始计步 if sceneEx.StartStep(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true case rule.StepCancel: // 取消计步 if sceneEx.CancelStep(playerEx) { returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true } returnFunc(chesstitians.OpResultCode_OPRC_Error) return true } case rule.PlayerOpTest: // 测试 强制同步给所有的玩家 returnFunc(chesstitians.OpResultCode_OPRC_Sucess) return true case rule.PlayerOpWin: if common.Config.IsDevMode { for _, seat := range sceneEx.seats { if seat != nil { if seat.GetSnId() == playerEx.GetSnId() { sceneEx.winSnId = seat.GetSnId() break } } } returnFunc(chesstitians.OpResultCode_OPRC_Sucess) } return true } return true } func (this *SceneStatePlayerOp) OnPlayerOpAI(s *base.Scene, p *base.Player, opcode int, params []int64) bool { return true } // 玩家事件 func (this *SceneStatePlayerOp) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *SceneHandCardStateChesstitians) OnPlayerEvent, GetSceneId()=", s.GetSceneId(), " player=", p.Name, " evtcode=", evtcode) this.SceneStateBase.OnPlayerEvent(s, p, evtcode, params) } func (this *SceneStatePlayerOp) OnTick(s *base.Scene) { this.SceneStateBase.OnTick(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { now := time.Now() f := func() { // 玩家操作超时,输 for k, v := range sceneEx.seats { if k != sceneEx.GetCurOpPos() && v != nil { sceneEx.winSnId = v.GetSnId() sceneEx.ChangeSceneState(rule.SceneStateBilled) break } } } if sceneEx.chess.GetRound() == 1 || sceneEx.chess.GetRound() == 2 { if now.Sub(sceneEx.StateStartTime) > rule.PlayerFirstOpTimeout { f() } } else { if now.Sub(sceneEx.StateStartTime) > rule.PlayerOpTimeout { f() } } curPlayer := sceneEx.seats[sceneEx.GetCurOpPos()] if time.Duration(curPlayer.getTotalTime())*time.Second >= rule.PlayerTotalTime { f() } } } //===================================== // SceneStateBilled 结算 //===================================== type SceneStateBilled struct { SceneStateBase } func (this *SceneStateBilled) GetState() int { return rule.SceneStateBilled } func (this *SceneStateBilled) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.SceneStateWaitPlayer, rule.SceneStateWaitStart: return true default: return false } } func (this *SceneStateBilled) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { return true } func (this *SceneStateBilled) OnEnter(s *base.Scene) { this.SceneStateBase.OnEnter(s) this.BroadcastRoomState(s, this.GetState()) sceneEx, ok := s.GetExtraData().(*SceneEx) if !ok { return } pack := &chesstitians.SCChesstitiansGameBilled{} chessType := model.ChesstitiansType{ GameId: int(sceneEx.GameId), RoomId: int32(sceneEx.GetSceneId()), RoomType: sceneEx.Scene.GetDBGameFree().GetSceneType(), NumOfGames: int32(sceneEx.Scene.NumOfGames), BankId: sceneEx.masterSnId, PlayerCount: rule.MaxNumOfPlayer, BaseScore: s.BaseScore, TaxRate: s.GetDBGameFree().GetTaxRate(), RoomMode: s.GetSceneMode(), } var winPlayer *PlayerEx var losePlayer *PlayerEx var draw bool for _, seat := range sceneEx.seats { if seat != nil { if sceneEx.winSnId == seat.GetSnId() { winPlayer = seat } else { losePlayer = seat } } } if winPlayer == nil { draw = true winPlayer = sceneEx.seats[0] losePlayer = sceneEx.seats[1] } if draw { // 平局 billData, chessPerson := sceneEx.ToBilled(winPlayer, losePlayer, rule.Draw) pack.Datas = append(pack.Datas, billData) chessType.PlayerData = append(chessType.PlayerData, chessPerson) //玩家2 billData1, chessPerson1 := sceneEx.ToBilled(losePlayer, winPlayer, rule.Draw) pack.Datas = append(pack.Datas, billData1) chessType.PlayerData = append(chessType.PlayerData, chessPerson1) } else { // 有输赢 billData, chessPerson := sceneEx.ToBilled(winPlayer, losePlayer, rule.Win) pack.Datas = append(pack.Datas, billData) chessType.PlayerData = append(chessType.PlayerData, chessPerson) // 输家 billData1, chessPerson1 := sceneEx.ToBilled(losePlayer, winPlayer, rule.Lose) pack.Datas = append(pack.Datas, billData1) chessType.PlayerData = append(chessType.PlayerData, chessPerson1) } proto.SetDefaults(pack) s.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansGameBilled), pack, 0) logger.Logger.Trace("ChesstitiansPacketID_PACKET_SCChesstitiansGameBilled gameFreeId:", sceneEx.GetGameFreeId(), ";pack:", pack) info, err := model.MarshalGameNoteByFIGHT(&chessType) if err == nil { isSave := false var logid string for _, o_player := range chessType.PlayerData { if !sceneEx.Testing && !o_player.IsRob { if logid == "" { logid, _ = model.AutoIncGameLogId() } var totalin, totalout int64 if o_player.GainCoin < 0 { totalin -= (o_player.GainCoin + o_player.GainTaxCoin) } else { totalout += (o_player.GainCoin + o_player.GainTaxCoin) } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) sceneEx.SaveFriendRecord(o_player.UserId, o_player.IsWin, o_player.GainCoin, sceneEx.GetBaseScore()) // 游戏数据统计 sceneEx.Statistics(&base.StaticParam{ SnId: o_player.UserId, Gain: o_player.GainCoin, GainTax: o_player.GainTaxCoin, IsAddTimes: true, HasRobotGaming: sceneEx.GetGamingRobotCnt() > 0, }) // 玩家游戏记录 sceneEx.SaveGamePlayerListLog(o_player.UserId, base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.Promoter, o_player.PackageTag, logid, o_player.InviterId, totalin, totalout, o_player.GainTaxCoin, 0, 0, o_player.GainCoin, validBet, validFlow, o_player.IsFirst, o_player.IsLeave)) isSave = true } } if isSave { // 牌局记录 sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) } } sceneEx.NotifySceneRoundPause() } // 玩家操作 func (this *SceneStateBilled) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.SceneStateBase.OnPlayerOp(s, p, opcode, params) { return true } sceneEx, ok := s.GetExtraData().(*SceneEx) if !ok { return true } if sceneEx == nil { return true } playerEx, ok := p.GetExtraData().(*PlayerEx) if !ok { return true } if playerEx == nil { return true } returnFunc := func(code chesstitians.OpResultCode) { if code == chesstitians.OpResultCode_OPRC_Sucess { sceneEx.BroadcastPlayerSCOp(playerEx.SnId, opcode, code, params) } else { // 若不能成功操作,仅发给操作的玩家 sceneEx.OnPlayerSCOp(p, opcode, code, params) } } switch int32(opcode) { case rule.PlayerOpNextPlay: // 再来一局 if playerEx.nextPlay { return false } playerEx.nextPlay = true returnFunc(chesstitians.OpResultCode_OPRC_Sucess) if sceneEx.nextSnId == 0 { sceneEx.nextSnId = playerEx.GetSnId() } if sceneEx.seats[0].nextPlay && sceneEx.seats[1].nextPlay || sceneEx.GetGameId() == common.GameId_ChesstitiansCambodianRobot { s.ChangeSceneState(rule.SceneStateWaitStart) } return true } return true } // 玩家事件 func (this *SceneStateBilled) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { this.SceneStateBase.OnPlayerEvent(s, p, evtcode, params) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { switch evtcode { case base.PlayerEventLeave: // 有人离开,解散房间 for _, v := range sceneEx.seats { if v != nil { sceneEx.PlayerLeave(v.Player, common.PlayerLeaveReason_OnBilled, true) } } } } } func (this *SceneStateBilled) OnTick(s *base.Scene) { this.SceneStateBase.OnTick(s) sceneEx, ok := s.GetExtraData().(*SceneEx) if !ok { return } // 有机器人,让机器人离开 for _, v := range sceneEx.seats { if v != nil && v.IsRob { sceneEx.PlayerLeave(v.Player, common.PlayerLeaveReason_OnBilled, true) } } if sceneEx.GetRealPlayerNum() == 1 { for _, v := range sceneEx.seats { if v != nil { sceneEx.PlayerLeave(v.Player, common.PlayerLeaveReason_OnBilled, true) } } } if sceneEx.GetPlayerCnt() == 0 { sceneEx.SceneDestroy(true) } } // 状态离开时 func (this *SceneStateBilled) OnLeave(s *base.Scene) { this.SceneStateBase.OnLeave(s) if sceneEx, ok := s.GetExtraData().(*SceneEx); ok { sceneEx.SetGaming(false) switch sceneEx.GetGameId() { case common.GameId_Chesstitians, common.GameId_ChesstitiansMakruk, common.GameId_ChesstitiansCambodian: hasLeave := false //剔除下线玩家 for i := 0; i < sceneEx.GetPlayerNum(); i++ { playerEx := sceneEx.seats[i] if playerEx == nil { continue } playerEx.Clear() if sceneEx.IsMatchScene() { continue } if !playerEx.IsOnLine() { sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_DropLine, true) hasLeave = true continue } // 机器人金币离场检查 if playerEx.IsRob { if s.CoinOverMaxLimit(playerEx.GetCoin(), playerEx.Player) { sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_Normal, true) hasLeave = true continue } } // 低于进场限额 if !s.CoinInLimit(playerEx.GetCoin()) { sceneEx.PlayerLeave(playerEx.Player, s.NotCoinInLimitType(playerEx.GetCoin()), true) hasLeave = true continue } } if !hasLeave && !sceneEx.IsRobFightGame() && !sceneEx.IsMatchScene() { s.TryDismissRob() } case common.GameId_ChesstitiansCambodianRobot: sceneEx.SceneDestroy(true) return } if s.CheckNeedDestroy() || (s.IsMatchScene() && (!s.GetMatch().GetIsFinals() || (s.GetMatch().GetIsFinals() && s.NumOfGames >= 2))) { // 非决赛打一场 决赛打两场 sceneEx.SceneDestroy(true) } s.TryRelease() } } func (this *ScenePolicyEntity) RegisteSceneState(state base.SceneState) { if state == nil { return } stateId := state.GetState() if stateId < 0 || stateId >= rule.SceneStateMax { return } this.states[stateId] = state } func (this *ScenePolicyEntity) GetSceneState(s *base.Scene, stateId int) base.SceneState { if stateId >= 0 && stateId < rule.SceneStateMax { return this.states[stateId] } return nil } func init() { ScenePolicyEntitySingleton.RegisteSceneState(&SceneStateWaitPlayer{}) ScenePolicyEntitySingleton.RegisteSceneState(&SceneStateWaitStart{}) ScenePolicyEntitySingleton.RegisteSceneState(&SceneStateChessInit{}) ScenePolicyEntitySingleton.RegisteSceneState(&SceneStatePlayerOp{}) ScenePolicyEntitySingleton.RegisteSceneState(&SceneStateBilled{}) core.RegisteHook(core.HOOK_BEFORE_START, func() error { base.RegisteScenePolicy(common.GameId_Chesstitians, 0, ScenePolicyEntitySingleton) base.RegisteScenePolicy(common.GameId_ChesstitiansMakruk, 0, ScenePolicyEntitySingleton) base.RegisteScenePolicy(common.GameId_ChesstitiansCambodian, 0, ScenePolicyEntitySingleton) base.RegisteScenePolicy(common.GameId_ChesstitiansCambodianRobot, 0, ScenePolicyEntitySingleton) return nil }) }