package clawdoll import ( "mongo.games.com/game/protocol/clawdoll" "time" "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/logger" "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/clawdoll" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/proto" ) var PolicyClawdollSingleton = &PolicyClawdoll{} type PolicyClawdoll struct { base.BaseScenePolicy states [rule.ClawDollSceneStateMax]base.SceneState } func (this *PolicyClawdoll) CreateSceneExData(s *base.Scene) interface{} { sceneEx := NewClawdollSceneData(s) if sceneEx != nil { if sceneEx.init() { s.ExtraData = sceneEx } } return sceneEx } func (this *PolicyClawdoll) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { playerEx := &PlayerEx{Player: p} if playerEx != nil { p.ExtraData = playerEx } return playerEx } func (this *PolicyClawdoll) OnStart(s *base.Scene) { logger.Logger.Trace("(this *PolicyClawdoll) OnStart, sceneId=", s.GetSceneId()) sceneEx := NewClawdollSceneData(s) if sceneEx != nil { if sceneEx.init() { s.ExtraData = sceneEx s.ChangeSceneState(rule.ClawDollSceneStateWait) } } } func (this *PolicyClawdoll) OnStop(s *base.Scene) { logger.Logger.Trace("(this *PolicyClawdoll) OnStop , sceneId=", s.GetSceneId()) } func (this *PolicyClawdoll) OnTick(s *base.Scene) { if s == nil { return } if s.SceneState != nil { s.SceneState.OnTick(s) } } func (this *PolicyClawdoll) OnPlayerEnter(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.SnId) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { pos := -1 for i := 0; i < sceneEx.GetPlayerNum(); i++ { if sceneEx.seats[i] == nil { pos = i break } } if pos != -1 { playerEx := &PlayerEx{Player: p} sceneEx.seats[pos] = playerEx sceneEx.players[p.SnId] = playerEx baseScore := sceneEx.GetBaseScore() p.Pos = pos p.ExtraData = playerEx playerEx.Clear(baseScore) if sceneEx.Gaming { p.MarkFlag(base.PlayerState_WaitNext) p.UnmarkFlag(base.PlayerState_Ready) } //给自己发送房间信息 this.SendRoomInfo(s, p, sceneEx) s.FirePlayerEvent(p, base.PlayerEventEnter, nil) } } } func (this *PolicyClawdoll) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.SnId) if s == nil || p == nil { return } if !this.CanChangeCoinScene(s, p) { return } sceneEx, ok := s.ExtraData.(*SceneEx) if !ok { return } playerEx, ok := p.ExtraData.(*PlayerEx) if !ok { return } isBilled := false // 游戏已开始,玩家离开,备份玩家数据 if sceneEx.Gaming { sceneEx.BackupPlayer(playerEx, isBilled) } // 清理玩家数据 sceneEx.OnPlayerLeave(p, reason) s.FirePlayerEvent(p, base.PlayerEventLeave, nil) } func (this *PolicyClawdoll) OnPlayerDropLine(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.SnId) s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) } func (this *PolicyClawdoll) OnPlayerRehold(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if _, ok := p.ExtraData.(*PlayerEx); ok { //发送房间信息给自己 if p.IsGameing() { p.MarkFlag(base.PlayerState_Ready) } this.SendRoomInfo(s, p, sceneEx) s.FirePlayerEvent(p, base.PlayerEventRehold, nil) } } } func (this *PolicyClawdoll) OnPlayerReturn(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if _, ok := p.ExtraData.(*PlayerEx); ok { //发送房间信息给自己 if p.IsGameing() { p.MarkFlag(base.PlayerState_Ready) } this.SendRoomInfo(s, p, sceneEx) s.FirePlayerEvent(p, base.PlayerEventReturn, nil) } } } func (this *PolicyClawdoll) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if s == nil || p == nil { return false } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerOp, sceneId=", s.GetSceneId(), " player=", p.SnId, " opcode=", opcode, " params=", params) if s.SceneState != nil { p.LastOPTimer = time.Now() p.Trusteeship = 0 return s.SceneState.OnPlayerOp(s, p, opcode, params) } return true } func (this *PolicyClawdoll) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { if s == nil || p == nil { return } logger.Logger.Trace("(this *PolicyClawdoll) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " eventcode=", evtcode, " params=", params) if s.SceneState != nil { s.SceneState.OnPlayerEvent(s, p, evtcode, params) } } func (this *PolicyClawdoll) IsCompleted(s *base.Scene) bool { if s == nil { return false } if sceneEx, ok := s.ExtraData.(*SceneEx); ok { return !sceneEx.Gaming } return false } func (this *PolicyClawdoll) IsCanForceStart(s *base.Scene) bool { if sceneEx, ok := s.ExtraData.(*SceneEx); ok { return len(s.Players) >= 2 && !sceneEx.Gaming } return false } func (this *PolicyClawdoll) ForceStart(s *base.Scene) { if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if sceneEx.SceneState.GetState() == rule.ClawDollSceneStateWait { s.ChangeSceneState(rule.ClawDollSceneStateStart) } } } // 当前状态能否退出游戏 func (this *PolicyClawdoll) 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 *PolicyClawdoll) SendRoomInfo(s *base.Scene, p *base.Player, sceneEx *SceneEx) { pack := sceneEx.ClawdollCreateRoomInfoPacket(s, p) p.SendToClient(int(clawdoll.CLAWDOLLPacketID_PACKET_SC_CLAWDOLL_ROOMINFO), pack) } // 广播房间状态 func ClawdollBroadcastRoomState(s *base.Scene, params ...float32) { pack := &clawdoll.SCCLAWDOLLRoomState{ State: proto.Int(s.SceneState.GetState()), Params: params, } s.Broadcast(int(clawdoll.CLAWDOLLPacketID_PACKET_SC_CLAWDOLL_ROOMSTATE), pack, 0) } //===================================== // BaseState 状态基类 //===================================== type BaseState struct { } func (this *BaseState) GetTimeout(s *base.Scene) int { if sceneEx, ok := s.ExtraData.(*SceneEx); ok { return int(time.Now().Sub(sceneEx.StateStartTime) / time.Second) } return 0 } func (this *BaseState) CanChangeTo(s base.SceneState) bool { return true } func (this *BaseState) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { //playerEx, ok := p.ExtraData.(*PlayerEx) //if !ok { // return false //} // //if !playerEx.CanLeaveScene(s.GetSceneState().GetState()) { // return false //} return true } func (this *BaseState) OnEnter(s *base.Scene) { if sceneEx, ok := s.ExtraData.(*SceneEx); ok { sceneEx.StateStartTime = time.Now() } } func (this *BaseState) OnLeave(s *base.Scene) {} func (this *BaseState) OnTick(s *base.Scene) { } func (this *BaseState) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { return false } func (this *BaseState) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { } //===================================== // StateWait 等待中 //===================================== type StateWait struct { BaseState } func (this *StateWait) GetState() int { return rule.ClawDollSceneStateWait } func (this *StateWait) CanChangeTo(s base.SceneState) bool { if s.GetState() == rule.ClawDollSceneStateStart { return true } return false } func (this *StateWait) GetTimeout(s *base.Scene) int { return this.BaseState.GetTimeout(s) } func (this *StateWait) OnEnter(s *base.Scene) { this.BaseState.OnEnter(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if s.Gaming { s.NotifySceneRoundPause() } s.Gaming = false ClawdollBroadcastRoomState(s, float32(0), float32(0)) if sceneEx.CanStart() { s.ChangeSceneState(rule.ClawDollSceneStateStart) } } } // 玩家事件 func (this *StateWait) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *StateWait) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode) this.BaseState.OnPlayerEvent(s, p, evtcode, params) if _, ok := s.ExtraData.(*SceneEx); ok { switch evtcode { case base.PlayerEventLeave: case base.PlayerEventEnter: if !p.IsReady() { p.MarkFlag(base.PlayerState_Ready) p.SyncFlag() } } } } func (this *StateWait) OnTick(s *base.Scene) { this.BaseState.OnTick(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if s.CheckNeedDestroy() { sceneEx.SceneDestroy(true) return } if time.Now().Sub(sceneEx.StateStartTime) > rule.ClawDollSceneWaitTimeout { //切换到准备开局状态 if sceneEx.CanStart() { s.ChangeSceneState(rule.ClawDollSceneStateStart) } } } } //===================================== // StateStart 开始倒计时 //===================================== type StateStart struct { BaseState } func (this *StateStart) GetState() int { return rule.ClawDollSceneStateStart } func (this *StateStart) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.ClawDollSceneStatePlayGame: return true } return false } func (this *StateStart) OnEnter(s *base.Scene) { this.BaseState.OnEnter(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { ClawdollBroadcastRoomState(s, float32(0), float32(0)) s.Gaming = false sceneEx.GameNowTime = time.Now() sceneEx.NumOfGames++ } } func (this *StateStart) OnTick(s *base.Scene) { this.BaseState.OnTick(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if time.Now().Sub(sceneEx.StateStartTime) > rule.ClawDollSceneStartTimeout { //切换到等待操作状态 if sceneEx.CanStart() { s.ChangeSceneState(rule.ClawDollSceneStatePlayGame) } else { s.ChangeSceneState(rule.ClawDollSceneStateWait) } } } } func (this *StateStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if this.BaseState.OnPlayerOp(s, p, opcode, params) { return true } return false } func (this *StateStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { logger.Logger.Trace("(this *StateStart) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode) this.BaseState.OnPlayerEvent(s, p, evtcode, params) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { switch evtcode { case base.PlayerEventLeave: if !sceneEx.CanStart() { s.ChangeSceneState(rule.ClawDollSceneStateWait) } case base.PlayerEventEnter: if !p.IsReady() { p.MarkFlag(base.PlayerState_Ready) p.SyncFlag() } } } } // ===================================== // PlayGame 游戏中 // ===================================== type PlayGame struct { BaseState } func (this *PlayGame) GetState() int { return rule.ClawDollSceneStatePlayGame } func (this *PlayGame) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.ClawDollSceneStateBilled: return true } return false } func (this *PlayGame) OnEnter(s *base.Scene) { logger.Logger.Trace("(this *PlayGame) OnEnter, sceneid=", s.GetSceneId()) this.BaseState.OnEnter(s) s.Gaming = true ClawdollBroadcastRoomState(s, float32(0), float32(0)) } func (this *PlayGame) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { logger.Logger.Trace("StatePlayGame OnPlayerOp-----SnId:", p.SnId, " opcode: ", opcode, " params:", params) if this.BaseState.OnPlayerOp(s, p, opcode, params) { return true } return false } func (this *PlayGame) OnTick(s *base.Scene) { this.BaseState.OnTick(s) } //===================================== // StateBilled 结算 //===================================== type StateBilled struct { BaseState } func (this *StateBilled) GetState() int { return rule.ClawDollSceneStateBilled } func (this *StateBilled) CanChangeTo(s base.SceneState) bool { switch s.GetState() { case rule.ClawDollSceneStateStart: return true } return false } func (this *StateBilled) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { return false } func (this *StateBilled) OnEnter(s *base.Scene) { logger.Logger.Trace("(this *StateBilled) OnEnter, sceneid=", s.GetSceneId()) this.BaseState.OnEnter(s) } func (this *StateBilled) OnLeave(s *base.Scene) { logger.Logger.Trace("(this *StateBilled) OnLeave, sceneid=", s.GetSceneId()) this.BaseState.OnLeave(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { sceneEx.PlayerBackup = make(map[int32]*PlayerData) if s.CheckNeedDestroy() { sceneEx.SceneDestroy(true) } } } func (this *StateBilled) OnTick(s *base.Scene) { this.BaseState.OnTick(s) if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if time.Now().Sub(sceneEx.StateStartTime) > rule.ClawDollSceneBilledTimeout { if sceneEx.CanStart() { s.ChangeSceneState(rule.ClawDollSceneStateStart) } else { s.ChangeSceneState(rule.ClawDollSceneStateWait) } return } } } // // ////////////////////////////////////////////////////////////////////////////// func (this *PolicyClawdoll) RegisteSceneState(state base.SceneState) { if state == nil { return } stateid := state.GetState() if stateid < 0 || stateid >= rule.ClawDollSceneStateMax { return } this.states[stateid] = state } func (this *PolicyClawdoll) GetSceneState(s *base.Scene, stateid int) base.SceneState { if stateid >= 0 && stateid < rule.ClawDollSceneStateMax { return this.states[stateid] } return nil } func init() { PolicyClawdollSingleton.RegisteSceneState(&StateWait{}) PolicyClawdollSingleton.RegisteSceneState(&StateStart{}) PolicyClawdollSingleton.RegisteSceneState(&PlayGame{}) PolicyClawdollSingleton.RegisteSceneState(&StateBilled{}) core.RegisteHook(core.HOOK_BEFORE_START, func() error { base.RegisteScenePolicy(common.GameId_Clawdoll, 0, PolicyClawdollSingleton) return nil }) }