package caishen import ( "fmt" "math" "math/rand" "os" "strconv" "sync" "time" "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/basic" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/task" "mongo.games.com/goserver/core/timer" "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/caishen" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/caishen" "mongo.games.com/game/protocol/server" ) //////////////////////////////////////////////////////////////////////////////// //财神 //////////////////////////////////////////////////////////////////////////////// // 房间内主要逻辑 var ScenePolicyCaiShenSington = &ScenePolicyCaiShen{} type ScenePolicyCaiShen struct { base.BaseScenePolicy states [CaiShenSceneStateMax]base.SceneState } // 创建场景扩展数据 func (this *ScenePolicyCaiShen) CreateSceneExData(s *base.Scene) interface{} { sceneEx := NewCaiShenSceneData(s) if sceneEx != nil { if sceneEx.init() { s.ExtraData = sceneEx } } return sceneEx } // 创建玩家扩展数据 func (this *ScenePolicyCaiShen) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { playerEx := &CaiShenPlayerData{Player: p} if playerEx != nil { p.ExtraData = playerEx } return playerEx } // 场景开启事件 func (this *ScenePolicyCaiShen) OnStart(s *base.Scene) { logger.Logger.Trace("(this *ScenePolicyCaiShen) OnStart, SceneId=", s.SceneId) sceneEx := NewCaiShenSceneData(s) if sceneEx != nil { if sceneEx.init() { s.ExtraData = sceneEx s.ChangeSceneState(CaiShenSceneStateStart) //改变当前的玩家状态 } } } // 场景关闭事件 func (this *ScenePolicyCaiShen) OnStop(s *base.Scene) { logger.Logger.Trace("(this *ScenePolicyCaiShen) OnStop , SceneId=", s.SceneId) if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { sceneEx.SaveData(true) } } // 场景心跳事件 func (this *ScenePolicyCaiShen) OnTick(s *base.Scene) { if s == nil { return } if s.SceneState != nil { s.SceneState.OnTick(s) } } // 玩家进入事件 func (this *ScenePolicyCaiShen) OnPlayerEnter(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerEnter, SceneId=", s.SceneId, " player=", p.SnId) if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { playerEx := &CaiShenPlayerData{Player: p} playerEx.init(s) // 玩家当前信息初始化 playerEx.score = sceneEx.DbGameFree.GetBaseScore() // 底注 sceneEx.players[p.SnId] = playerEx p.ExtraData = playerEx CaiShenSendRoomInfo(s, p, sceneEx, playerEx, nil) s.FirePlayerEvent(p, base.PlayerEventEnter, nil) //回调会调取 onPlayerEvent事件 } } // 玩家离开事件 func (this *ScenePolicyCaiShen) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerLeave, SceneId=", s.SceneId, " player=", p.SnId) if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { if this.CanChangeCoinScene(s, p) { if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { playerEx.SavePlayerGameData(s.KeyGamefreeId) } sceneEx.OnPlayerLeave(p, reason) s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) } } } // 玩家掉线 func (this *ScenePolicyCaiShen) OnPlayerDropLine(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerDropLine, SceneId=", s.SceneId, " player=", p.SnId) s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { if sceneEx.Gaming { return } } } // 玩家重连 func (this *ScenePolicyCaiShen) OnPlayerRehold(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerRehold, SceneId=", s.SceneId, " player=", p.Name) //if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { // if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { //发送房间信息给自己 //CaiShenSendRoomInfo(s, p, sceneEx, playerEx) s.FirePlayerEvent(p, base.PlayerEventRehold, nil) // } //} } // 玩家返回房间 func (this *ScenePolicyCaiShen) OnPlayerReturn(s *base.Scene, p *base.Player) { if s == nil || p == nil { return } logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerReturn, SceneId=", s.SceneId, " player=", p.Name) if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { //发送房间信息给自己 CaiShenSendRoomInfo(s, p, sceneEx, playerEx, playerEx.billedData) s.FirePlayerEvent(p, base.PlayerEventReturn, nil) } } } // 玩家操作 func (this *ScenePolicyCaiShen) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { if s == nil || p == nil { return false } if s.SceneState != nil { return s.SceneState.OnPlayerOp(s, p, opcode, params) } return true } // 玩家事件 func (this *ScenePolicyCaiShen) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { if s == nil || p == nil { return } if s.SceneState != nil { s.SceneState.OnPlayerEvent(s, p, evtcode, params) } } // 是否完成了整个牌局 func (this *ScenePolicyCaiShen) IsCompleted(s *base.Scene) bool { return false } // 是否可以强制开始 func (this *ScenePolicyCaiShen) IsCanForceStart(s *base.Scene) bool { return true } // 当前状态能否换桌 func (this *ScenePolicyCaiShen) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { if s == nil || p == nil { return true } if s.SceneState != nil { return s.SceneState.CanChangeCoinScene(s, p) } return true } func (this *ScenePolicyCaiShen) RegisteSceneState(state base.SceneState) { if state == nil { return } stateid := state.GetState() if stateid < 0 || stateid >= CaiShenSceneStateMax { return } this.states[stateid] = state } func (this *ScenePolicyCaiShen) GetSceneState(s *base.Scene, stateid int) base.SceneState { if stateid >= 0 && stateid < CaiShenSceneStateMax { return ScenePolicyCaiShenSington.states[stateid] } return nil } func (this *ScenePolicyCaiShen) GetJackPotVal(s *base.Scene) int64 { if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { if sceneEx.lastJackpotValue != sceneEx.jackpot.VirtualJK { return sceneEx.jackpot.VirtualJK } } return 0 } func CaiShenSendRoomInfo(s *base.Scene, p *base.Player, sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerData, data *caishen.GameBilledData) { logger.Logger.Trace("-------------------发送房间消息 ", s.RoomId, p.SnId) pack := &caishen.SCCaiShenRoomInfo{ RoomId: proto.Int(s.SceneId), Creator: proto.Int32(s.Creator), GameId: proto.Int(s.GameId), RoomMode: proto.Int(s.GameMode), Params: common.CopySliceInt64ToInt32(s.Params), State: proto.Int(s.SceneState.GetState()), Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), GameFreeId: proto.Int32(s.DbGameFree.Id), BilledData: data, } if playerEx != nil { pd := &caishen.CaiShenPlayerData{ SnId: proto.Int32(playerEx.SnId), Name: proto.String(playerEx.Name), Head: proto.Int32(playerEx.Head), Sex: proto.Int32(playerEx.Sex), Coin: proto.Int64(playerEx.Coin), HeadOutLine: proto.Int32(playerEx.HeadOutLine), VIP: proto.Int32(playerEx.VIP), } pack.Players = append(pack.Players, pd) //for _, value := range playerEx.cards { // pack.Cards = append(pack.Cards, int32(value)) //} pack.BetLines = playerEx.betLines pack.FreeTimes = proto.Int32(playerEx.freeTimes) pack.Chip = proto.Int32(s.DbGameFree.BaseScore) pack.SpinID = proto.Int64(playerEx.spinID) if playerEx.totalPriceBonus > 0 { switch playerEx.bonusStage { case 0: pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) case 1: if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout*2 { playerEx.CleanBonus() } else if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout { playerEx.bonusStage = 2 playerEx.bonusStartTime += CaiShenBonusGameStageTimeout pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) } else { pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusGameIconData...) pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusOpRecord...) } case 2: if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout { playerEx.CleanBonus() } else { pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) } } } if playerEx.totalPriceBonus > 0 { pack.TotalPriceBonus = proto.Int64(playerEx.totalPriceBonus) pack.BonusGame = playerEx.bonusGame pack.BonusX = playerEx.bonusX } } proto.SetDefaults(pack) p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_ROOMINFO), pack) } type SceneStateCaiShenStart struct { } // 获取当前场景状态 func (this *SceneStateCaiShenStart) GetState() int { return CaiShenSceneStateStart } // 是否可以切换状态到 func (this *SceneStateCaiShenStart) CanChangeTo(s base.SceneState) bool { return true } // 当前状态能否换桌 func (this *SceneStateCaiShenStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { if _, ok := p.ExtraData.(*CaiShenPlayerData); ok { return true } return true } func (this *SceneStateCaiShenStart) GetTimeout(s *base.Scene) int { return 0 } func (this *SceneStateCaiShenStart) OnEnter(s *base.Scene) { if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { logger.Logger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.SceneId, len(sceneEx.players)) sceneEx.StateStartTime = time.Now() pack := &caishen.SCCaiShenRoomState{ State: proto.Int(this.GetState()), } proto.SetDefaults(pack) s.Broadcast(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_ROOMSTATE), pack, 0) } } func (this *SceneStateCaiShenStart) OnLeave(s *base.Scene) {} func (this *SceneStateCaiShenStart) OnTick(s *base.Scene) { if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { sceneEx.AIAddJackPot() sceneEx.AIBurstJackPot() sceneEx.KickPlayerByTime() } } func (this *SceneStateCaiShenStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { playerEx, ok := p.ExtraData.(*CaiShenPlayerData) if !ok { return false } sceneEx, ok := s.ExtraData.(*CaiShenSceneData) if !ok { return false } if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { //离开有统计 sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) return false } switch opcode { case CaiShenPlayerOpStart: //开始 //if !caiShenBenchTest { // caiShenBenchTest = true // //for i := 0; i < 10; i++ { // // //this.BenchTest(s, p) // // this.WinTargetBenchTest(s, p) // //} // this.MultiplayerBenchTest(s) // return true //} //参数是否合法 //params 参数0底注,后面跟客户端选择的线n条线(1<=n<=25),客户端线是从1开始算起1~25条线 if len(params) < 2 || len(params) > rule.LINENUM+1 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } //先做底注校验 if sceneEx.DbGameFree.GetBaseScore() != int32(params[0]) { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } playerEx.score = int32(params[0]) // 单线押注数 // 小游戏未结束 不能进行下一次旋转 if playerEx.totalPriceBonus > 0 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } //判断线条是否重复,是否合法 lineFlag := make(map[int64]bool) lineParams := make([]int64, 0) for i := 1; i < len(params); i++ { lineNum := params[i] if lineNum >= 1 && lineNum <= int64(rule.LINENUM) && !lineFlag[lineNum] { lineParams = append(lineParams, lineNum) lineFlag[lineNum] = true } else { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } } //没有选线参数 if len(lineParams) == 0 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } //获取总投注金额(所有线的总投注) | 校验玩家余额是否足够 totalBetValue := (int64(len(lineParams))) * params[0] if playerEx.freeTimes <= 0 && totalBetValue > playerEx.Coin { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_CoinNotEnough, params) return false } else if playerEx.freeTimes <= 0 && int64(sceneEx.DbGameFree.GetBetLimit()) > playerEx.Coin { //押注限制 this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_CoinNotEnough, params) return false } p.LastOPTimer = time.Now() sceneEx.GameNowTime = time.Now() sceneEx.NumOfGames++ p.GameTimes++ //playerEx.StartCoin = playerEx.Coin //获取当前水池的上下文环境 sceneEx.CpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) //税收比例 taxRate := sceneEx.DbGameFree.GetTaxRate() if taxRate < 0 || taxRate > 10000 { logger.Logger.Tracef("CaiShenErrorTaxRate [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate) taxRate = 500 } //水池设置 coinPoolSetting := base.CoinPoolMgr.GetCoinPoolSetting(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) //baseRate := coinPoolSetting.GetBaseRate() //基础赔率 ctroRate := coinPoolSetting.GetCtrlRate() //调节赔率 暗税系数 jackpotRate := ctroRate //奖池系数 logger.Logger.Tracef("CaiShenRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) playerEx.IsFNovice(sceneEx.KeyGameId) isFoolPlayer := playerEx.IsFoolPlayer[sceneEx.KeyGameId] var gamePoolCoin int64 if isFoolPlayer { gamePoolCoin = base.CoinPoolMgr.GetNoviceCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 } else { gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 } prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 // 奖池参数 var jackpotParam = sceneEx.DbGameFree.GetJackpot() var jackpotInit = int64(jackpotParam[rule.CAISHEN_JACKPOT_InitJackpot]) * int64(sceneEx.DbGameFree.GetBaseScore()) //奖池初始值 var jackpotFundAdd, prizeFundAdd int64 if playerEx.freeTimes <= 0 { //正常模式才能记录用户的押注变化,免费模式不能改变押注 playerEx.betLines = lineParams // 选线记录 jackpotFundAdd = int64(math.Floor(float64(totalBetValue) * (float64(jackpotRate) / 10000.0))) //奖池要增加的金额 prizeFundAdd = totalBetValue - jackpotFundAdd playerEx.TotalBet += totalBetValue //总下注额(从进房间开始,包含多局游戏的下注) //扣除投注金币 p.AddCoin(-totalBetValue, common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, -totalBetValue, true) if !p.IsRob && !sceneEx.Testing { // 推送金币 sceneEx.PushCoinPool(prizeFundAdd, isFoolPlayer) //base.CoinPoolMgr.PushCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, int64(float64(totalBetValue)*(float64(10000-ctroRate)/10000.0))) } ////统计参与游戏次数 //if !sceneEx.Testing && !playerEx.IsRob { // pack := &server.GWSceneEnd{ // GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), // Players: []*server.PlayerCtx{&server.PlayerCtx{SnId: proto.Int32(playerEx.SnId), Coin: proto.Int64(playerEx.Coin)}}, // } // proto.SetDefaults(pack) // sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEEND), pack) //} } else { //免费次数时,不能改线改选线 totalBetValue = 0 } writeBlackTryTimes := 0 WriteBlack: slotData := make([]int, 0) var spinRes CaiShenSpinResult var slotDataIsOk bool for { var symbolType rule.Symbol if gamePoolCoin < coinPoolSetting.GetLowerLimit() { // userInfo.prizeFund < limit * roomId symbolType = rule.SYMBOL1 } else { symbolType = rule.SYMBOL2 } slotData, _ = rule.GenerateSlotsData_v2(symbolType) spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) // 免费次数时 不允许爆奖 if playerEx.freeTimes > 0 && spinRes.IsJackpot { break } if spinRes.JackpotCnt > 1 { break } if spinRes.IsJackpot { if sceneEx.jackpot.Small < sceneEx.jackpot.VirtualJK { break } } spinCondition := prizeFund + prizeFundAdd - (spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot) spinCondition += jackpotFundAdd + sceneEx.jackpot.VirtualJK - jackpotInit win := spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot // 现金池不足时 重新发牌 if spinCondition < 0 && win > totalBetValue { if !spinRes.IsJackpot { // 非爆奖 水池不足 不再进行黑白名单调控 writeBlackTryTimes = 999 } break } // 非爆奖时 不允许赢取太大的奖励 var limitBigWin int64 = 50 if spinCondition < int64(coinPoolSetting.GetLowerLimit()) { //现金池不足时 limitBigWin = int64(jackpotParam[rule.CAISHEN_JACKPOT_LIMITWIN_PRIZELOW]) } else { limitBigWin = int64(jackpotParam[rule.CAISHEN_JACKPOT_LIMITWIN_PRIZEHIGH]) } if totalBetValue > 0 && !spinRes.IsJackpot && spinRes.TotalPrizeLine+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue*limitBigWin { break } // 小游戏次数限制 // 爆奖次数限制 slotDataIsOk = true break } if !slotDataIsOk { slotData = rule.MissData[rand.Intn(len(rule.MissData))] spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) } // 黑白名单调控 防止异常循环,添加上限次数 if writeBlackTryTimes < 100 && playerEx.CheckBlackWriteList(spinRes.TotalPrizeLine+spinRes.TotalPrizeJackpot+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue) { writeBlackTryTimes++ goto WriteBlack } else if writeBlackTryTimes >= 100 && writeBlackTryTimes != 999 { logger.Logger.Warnf("CaiShenWriteBlackTryTimesOver [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, gamePoolCoin, playerEx.WBLevel) } // 奖池水池处理 if spinRes.IsJackpot { sceneEx.jackpot.Small -= sceneEx.jackpot.VirtualJK if sceneEx.jackpot.Small < 0 { sceneEx.jackpot.Small = 0 } sceneEx.jackpot.VirtualJK = jackpotInit } else { sceneEx.jackpot.Small += jackpotFundAdd sceneEx.jackpot.VirtualJK += jackpotFundAdd } // 玩家赢钱 totalWinScore := spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot if totalWinScore > 0 || len(spinRes.BonusX) > 0 { p.AddCoin(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue(), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, true) if !p.IsRob && !sceneEx.Testing { sceneEx.PopCoinPool(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, isFoolPlayer) //base.CoinPoolMgr.PopCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) } playerEx.taxCoin = spinRes.TotalTaxScore playerEx.AddServiceFee(playerEx.taxCoin) } sceneEx.StaticsLaba(&base.StaticLabaParam{ SnId: playerEx.SnId, Gain: totalWinScore + spinRes.BonusGame.GetTotalPrizeValue() - totalBetValue, GainTax: spinRes.TotalTaxScore, IsAddTimes: true, }) this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, append(params[:1], playerEx.betLines...)) //免费次数 var isFreeFlag bool if playerEx.freeTimes > 0 { playerEx.freeTimes-- isFreeFlag = true } playerEx.freeTimes += spinRes.AddFreeTimes rule.SpinID++ playerEx.spinID = rule.SpinID playerEx.cards = spinRes.SlotsData playerEx.winCoin = spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + spinRes.BonusGame.GetTotalPrizeValue() + playerEx.taxCoin playerEx.linesWinCoin = spinRes.TotalPrizeLine playerEx.jackpotWinCoin = spinRes.TotalPrizeJackpot playerEx.smallGameWinCoin = spinRes.BonusGame.GetTotalPrizeValue() playerEx.CurrentBet = totalBetValue playerEx.CurrentTax = playerEx.taxCoin // 小游戏超时处理 if len(spinRes.BonusX) > 0 { playerEx.totalPriceBonus = spinRes.BonusGame.GetTotalPrizeValue() playerEx.bonusGame = &spinRes.BonusGame playerEx.bonusX = spinRes.BonusX logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) // playerEx.bonusTimerHandle, _ = timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { // this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) // return true // }), nil, CaiShenBonusGameTimeout, 1) } playerEx.billedData = &caishen.GameBilledData{ SpinID: proto.Int64(playerEx.spinID), SlotsData: spinRes.SlotsData, AddFreeSpin: proto.Int32(spinRes.AddFreeTimes), IsJackpot: proto.Bool(spinRes.IsJackpot), PrizeLines: spinRes.LinesInfo, TotalPrizeValue: proto.Int64(totalWinScore), TotalPaylinePrizeValue: proto.Int64(spinRes.TotalPrizeLine), TotalJackpotValue: proto.Int64(spinRes.TotalPrizeJackpot), Balance: proto.Int64(playerEx.Coin - spinRes.BonusGame.GetTotalPrizeValue()), FreeSpins: proto.Int32(playerEx.freeTimes), Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), BonusX: spinRes.BonusX, BonusGame: &spinRes.BonusGame, } pack := &caishen.SCCaiShenGameBilled{ BilledData: playerEx.billedData, } proto.SetDefaults(pack) logger.Logger.Infof("CaiShenPlayerOpStart %v", pack) p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_GAMEBILLED), pack) // 记录本次操作 playerEx.RollGameType.BaseResult.WinTotal = pack.BilledData.GetTotalPrizeValue() + pack.BilledData.GetBonusGame().GetTotalPrizeValue() playerEx.RollGameType.BaseResult.IsFree = isFreeFlag playerEx.RollGameType.BaseResult.AllWinNum = int32(len(pack.BilledData.PrizeLines)) playerEx.RollGameType.BaseResult.WinRate = spinRes.TotalWinRate playerEx.RollGameType.BaseResult.Cards = pack.BilledData.GetSlotsData() playerEx.RollGameType.WinLines = spinRes.WinLines playerEx.RollGameType.BaseResult.WinLineScore = pack.BilledData.TotalPaylinePrizeValue playerEx.RollGameType.BaseResult.WinJackpot = pack.BilledData.GetTotalJackpotValue() playerEx.RollGameType.BaseResult.WinSmallGame = pack.BilledData.GetBonusGame().GetTotalPrizeValue() playerEx.RollGameType.BaseResult.IsFoolPlayer = isFoolPlayer CaiShenCheckAndSaveLog(sceneEx, playerEx) // 广播奖池 if totalBetValue == 0 && !spinRes.IsJackpot { // 没改变奖池 return true } // 添加进开奖记录里面 if spinRes.IsJackpot { sceneEx.RecordBurstLog(playerEx.Name, pack.BilledData.GetTotalJackpotValue(), playerEx.CurrentBet) } logger.Logger.Tracef("---caishen---当前奖池:真人[%v] 虚拟[%v]", sceneEx.jackpot.Small, sceneEx.jackpot.VirtualJK) case CaiShenBurstHistory: sceneEx.BurstHistory(playerEx) case CaiShenPlayerHistory: task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { spinid := strconv.FormatInt(int64(playerEx.SnId), 10) gpl := model.GetPlayerListByHallEx(p.SnId, p.Platform, 0, 80, 0, 0, 0, s.DbGameFree.GetGameClass(), s.GameId) pack := &caishen.SCCaiShenPlayerHistory{} for _, v := range gpl.Data { //if v.GameDetailedLogId == "" { // logger.Logger.Error("CaiShenPlayerHistory GameDetailedLogId is nil") // break //} //gdl := model.GetPlayerHistory(p.Platform, v.GameDetailedLogId) //if gdl == nil { // logger.Logger.Error("CaiShenPlayerHistory gdl is nil") // continue //} //data, err := UnMarshalCaiShenGameNote(gdl.GameDetailedNote) //if err != nil { // logger.Logger.Errorf("UnMarshalCaiShenGameNote error:%v", err) //} //gnd := data.(*GameResultLog) player := &caishen.CaiShenPlayerHistoryInfo{ SpinID: proto.String(spinid), CreatedTime: proto.Int64(int64(v.Ts)), TotalBetValue: proto.Int64(v.BetAmount), TotalPriceValue: proto.Int64(v.WinTotal), IsFree: proto.Bool(v.IsFree), TotalBonusValue: proto.Int64(v.WinSmallGame), } pack.PlayerHistory = append(pack.PlayerHistory, player) } proto.SetDefaults(pack) logger.Logger.Info("CaiShenPlayerHistory: ", pack) return pack }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { if data == nil { logger.Logger.Error("CaiShenPlayerHistory data is nil") return } p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_PLAYERHISTORY), data) }), "CSGetCaiShenPlayerHistoryHandler").Start() case CaiShenBonusGame: //params 参数0 spinID //参数是否合法 if len(params) < 1 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } if playerEx.spinID != params[0] || playerEx.totalPriceBonus <= 0 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } if playerEx.bonusTimerHandle != timer.TimerHandle(0) { timer.StopTimer(playerEx.bonusTimerHandle) playerEx.bonusTimerHandle = timer.TimerHandle(0) } logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, []int64{playerEx.totalPriceBonus, playerEx.Coin}) playerEx.CleanBonus() case CaiShenBonusGameRecord: // params[0] 小游戏阶段: 0 小游戏动画开始 1 小游戏界面1 2 切换小游戏界面2 // params[1] 小游戏界面1时,选择奖项的界面位置信息 if len(params) < 1 || params[0] < 0 || params[0] > 2 || playerEx.totalPriceBonus <= 0 || (params[0] == 1 && len(params) < 2) { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } if params[0] == 0 { if playerEx.bonusStage > 0 || len(params) < 13 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } playerEx.bonusStage = 1 playerEx.bonusStartTime = time.Now().Unix() for i := 1; i < len(params); i++ { playerEx.bonusGameIconData = append(playerEx.bonusGameIconData, int32(params[i])) } } else if params[0] == 2 { if playerEx.bonusStage != 1 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } playerEx.bonusStage = 2 playerEx.bonusStartTime = time.Now().Unix() } else if params[0] == 1 { if params[1] < 0 { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } else if playerEx.bonusGame != nil && len(playerEx.bonusOpRecord) >= len(playerEx.bonusGame.BonusData) { this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) return false } playerEx.bonusOpRecord = append(playerEx.bonusOpRecord, int32(params[1])) } this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, params) } return true } func (this *SceneStateCaiShenStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { } // 发送玩家操作情况 func (this *SceneStateCaiShenStart) OnPlayerSToCOp(s *base.Scene, p *base.Player, pos int, opcode int, opRetCode caishen.OpResultCode, params []int64) { pack := &caishen.SCCaiShenOp{ SnId: proto.Int32(p.SnId), OpCode: proto.Int(opcode), OpRetCode: opRetCode, Params: params, } proto.SetDefaults(pack) p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_PLAYEROP), pack) } var caiShenBenchTest bool var caiShenBenchTestTimes int func (this *SceneStateCaiShenStart) BenchTest(s *base.Scene, p *base.Player) { const BENCH_CNT = 10000 setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) if caiShenBenchTestTimes == 0 { defaultVal := int64(setting.GetLowerLimit()) if oldPoolCoin != defaultVal { base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) } } caiShenBenchTestTimes++ fileName := fmt.Sprintf("caishen-%v-%d.csv", p.SnId, caiShenBenchTestTimes) file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) defer file.Close() if err != nil { file, err = os.Create(fileName) if err != nil { return } } file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") oldCoin := p.Coin p.Coin = 10000000 if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { for i := 0; i < BENCH_CNT; i++ { StartCoin := p.Coin freeTimes := playerEx.freeTimes poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) playerEx.UnmarkFlag(base.PlayerState_GameBreak) suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin taxCoin := playerEx.RollGameType.BaseResult.Tax str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) file.WriteString(str) if !suc { break } if playerEx.totalPriceBonus > 0 { this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) } } } p.Coin = oldCoin } func (this *SceneStateCaiShenStart) WinTargetBenchTest(s *base.Scene, p *base.Player) { const BENCH_CNT = 10000 var once = sync.Once{} once.Do(func() { setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) if caiShenBenchTestTimes == 0 { defaultVal := int64(setting.GetLowerLimit()) if oldPoolCoin != defaultVal { base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) } } }) caiShenBenchTestTimes++ fileName := fmt.Sprintf("caishen-win-%v-%d.csv", p.SnId, caiShenBenchTestTimes) file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) defer file.Close() if err != nil { file, err = os.Create(fileName) if err != nil { return } } file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") oldCoin := p.Coin switch s.DbGameFree.GetSceneType() { case 1: p.Coin = 100000 case 2: p.Coin = 500000 case 3: p.Coin = 1000000 case 4: p.Coin = 10000000 default: p.Coin = 100000 } var targetCoin = p.Coin + p.Coin/10 if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { for i := 0; p.Coin < targetCoin; i++ { StartCoin := p.Coin freeTimes := playerEx.freeTimes poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) playerEx.UnmarkFlag(base.PlayerState_GameBreak) suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin taxCoin := playerEx.RollGameType.BaseResult.Tax str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) file.WriteString(str) if !suc { break } if playerEx.totalPriceBonus > 0 { this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) } if i > BENCH_CNT { break } } } p.Coin = oldCoin } // MultiplayerBenchTest 多人同时测试 模拟正常环境 func (this *SceneStateCaiShenStart) MultiplayerBenchTest(s *base.Scene) { const BENCH_CNT = 10000 var once = sync.Once{} once.Do(func() { setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) if caiShenBenchTestTimes == 0 { defaultVal := int64(setting.GetLowerLimit()) if oldPoolCoin != defaultVal { base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) } } }) caiShenBenchTestTimes++ fileName := fmt.Sprintf("caishen-total-%v-%d.csv", s.DbGameFree.GetSceneType(), caiShenBenchTestTimes) file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) defer file.Close() if err != nil { file, err = os.Create(fileName) if err != nil { return } } file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") playersFile := make(map[int32]*os.File) oldCoins := make(map[int32]int64) hasCoin := 1000 * int64(s.DbGameFree.GetBaseScore()) robots := make(map[int32]bool) testPlayers := make(map[int32]*base.Player) for _, p := range s.Players { if p.IsRob { p.IsRob = false robots[p.SnId] = true } fileName := fmt.Sprintf("caishen-player%v-%v-%d.csv", p.SnId, s.DbGameFree.GetSceneType(), caiShenBenchTestTimes) file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) if err != nil { file, err = os.Create(fileName) if err != nil { return } } file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") playersFile[p.SnId] = file oldCoins[p.SnId] = p.Coin p.Coin = hasCoin hasCoin = int64(float64(hasCoin) * 1.6) testPlayers[p.SnId] = p } defer func() { for _, file := range playersFile { file.Close() } for snid, Coin := range oldCoins { if player := s.GetPlayer(snid); player != nil { player.Coin = Coin if robots[player.SnId] { player.IsRob = true } } } }() totalBet := int64(s.DbGameFree.GetBaseScore()) * int64(len(rule.AllBetLines)) for i := 0; i < BENCH_CNT; i++ { for snid, p := range testPlayers { if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { StartCoin := p.Coin if StartCoin < totalBet { continue } freeTimes := playerEx.freeTimes poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) playerEx.UnmarkFlag(base.PlayerState_GameBreak) suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin taxCoin := playerEx.RollGameType.BaseResult.Tax lineScore := float64(playerEx.RollGameType.BaseResult.WinRate*s.DbGameFree.GetBaseScore()) * float64(10000.0-s.DbGameFree.GetTaxRate()) / 10000.0 jackpotScore := outCoin - playerEx.RollGameType.BaseResult.WinSmallGame - int64(lineScore+0.00001) str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, playerEx.RollGameType.BaseResult.WinSmallGame, jackpotScore, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) file.WriteString(str) if pFile := playersFile[snid]; pFile != nil { pFile.WriteString(str) } if !suc { continue } if playerEx.totalPriceBonus > 0 { this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) } } } } } func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerData) { //统计金币变动 //log1 logger.Logger.Trace("CaiShenCheckAndSaveLog Save ", playerEx.SnId) //changeCoin := playerEx.Coin - playerEx.StartCoin changeCoin := playerEx.winCoin - playerEx.taxCoin - playerEx.CurrentBet startCoin := playerEx.Coin - changeCoin //playerEx.SaveSceneCoinLog(startCoin, changeCoin, // playerEx.Coin, playerEx.CurrentBet, playerEx.taxCoin, playerEx.winCoin, playerEx.jackpotWinCoin, playerEx.smallGameWinCoin) //log2 playerEx.RollGameType.BaseResult.ChangeCoin = changeCoin playerEx.RollGameType.BaseResult.BasicBet = sceneEx.DbGameFree.GetBaseScore() playerEx.RollGameType.BaseResult.RoomId = int32(sceneEx.SceneId) playerEx.RollGameType.BaseResult.AfterCoin = playerEx.Coin playerEx.RollGameType.BaseResult.BeforeCoin = startCoin playerEx.RollGameType.BaseResult.IsFirst = sceneEx.IsPlayerFirst(playerEx.Player) playerEx.RollGameType.BaseResult.PlayerSnid = playerEx.SnId playerEx.RollGameType.BaseResult.TotalBet = int32(playerEx.CurrentBet) playerEx.RollGameType.AllLine = int32(len(playerEx.betLines)) playerEx.RollGameType.BaseResult.FreeTimes = playerEx.freeTimes playerEx.RollGameType.UserName = playerEx.Name playerEx.RollGameType.BetLines = playerEx.betLines playerEx.RollGameType.BaseResult.Tax = playerEx.taxCoin playerEx.RollGameType.BaseResult.WBLevel = sceneEx.players[playerEx.SnId].WBLevel if playerEx.score > 0 { if !playerEx.IsRob { info, err := model.MarshalGameNoteByROLL(playerEx.RollGameType) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) logParam := &base.SaveGamePlayerListLogParam{ Platform: playerEx.Platform, Channel: playerEx.Channel, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, LogId: logid, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, } sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) } } } //统计输下注金币数 if !sceneEx.Testing && !playerEx.IsRob { playerBet := &server.PlayerData{ SnId: proto.Int32(playerEx.SnId), Bet: proto.Int64(playerEx.CurrentBet), Gain: proto.Int64(playerEx.RollGameType.BaseResult.ChangeCoin), Tax: proto.Int64(playerEx.taxCoin), Coin: proto.Int64(playerEx.GetCoin()), GameCoinTs: proto.Int64(playerEx.GameCoinTs), } gwPlayerBet := &server.GWPlayerData{ SceneId: proto.Int(sceneEx.SceneId), GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), } gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ HasRobotGaming: false, Data: gwPlayerBet, }) } playerEx.taxCoin = 0 playerEx.winCoin = 0 playerEx.linesWinCoin = 0 playerEx.jackpotWinCoin = 0 playerEx.smallGameWinCoin = 0 if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) } } func init() { ScenePolicyCaiShenSington.RegisteSceneState(&SceneStateCaiShenStart{}) core.RegisteHook(core.HOOK_BEFORE_START, func() error { base.RegisteScenePolicy(common.GameId_CaiShen, 0, ScenePolicyCaiShenSington) return nil }) }