package base import ( "fmt" "math" "math/rand" "strconv" "time" rawproto "google.golang.org/protobuf/proto" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/utils" srvlibproto "mongo.games.com/goserver/srvlib/protocol" "mongo.games.com/game/common" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/gamehall" "mongo.games.com/game/protocol/player" "mongo.games.com/game/protocol/server" "mongo.games.com/game/srvdata" ) const ReplayIdTf = "20060102150405" var sceneRandSeed = time.Now().UnixNano() var RobotSceneDBGameFreeSync = make(map[int]bool) type GameScene interface { SceneDestroy(force bool) } type CanRebindSnId interface { RebindPlayerSnId(oldSnId, newSnId int32) } // todo 结构优化 type Scene struct { *server.WGCreateScene ws *netlib.Session // 大厅服 Rand *rand.Rand // 随机数生成器 ExtraData interface{} // 房间数据 aiMgr AIMgr // WithLocalAI bool // disbandGen int //第几次解散申请 disbandParam []int64 //解散参数 disbandPos int32 //发起解散的玩家位置 disbandTs int64 //解散发起时间戳 realPlayerNum int //真实玩家人数 robotNum int //机器人数量 robotLimit int //最大限制机器人数量 robotNumLastInvite int //上次邀请机器人时的数量 NumOfGames int //局数 Players map[int32]*Player //参与者 audiences map[int32]*Player //观众 sp ScenePolicy //场景游戏策略 rr *ReplayRecorder //回放记录器 rrVer int32 //录像的协议版本号 SceneState SceneState //场景状态 StateStartTime time.Time //状态开始时间 stateEndTime time.Time //状态结束时间 GameStartTime time.Time //游戏开始计时时间 GameNowTime time.Time //当局游戏开始时间 nextInviteTime time.Time //下次邀请机器人时间 inviteInterval int64 //邀请间隔 pause bool Gaming bool destroyed bool completed bool Testing bool //是否为测试场 graceDestroy bool //等待销毁 replayAddId int32 KeyGameId string //游戏类型唯一ID KeyGamefreeId string //游戏场次唯一id KeyGameDif string GroupId int32 //分组id bEnterAfterStart bool //是否允许中途加入 ClubId int32 RoomId string //俱乐部那个包间 RoomPos int32 //房间桌号 PumpCoin int32 //抽水比例,同一个俱乐部下面的抽水比例是一定的,百分比 DealyTime int64 //结算延时时间 CpCtx model.CoinPoolCtx //水池环境 CpControlled bool //被水池控制了 timerRandomRobot int64 nogDismiss int //检查机器人离场时的局数(同一局只检查一次) SystemCoinOut int64 //本局游戏机器人营收 机器人赢:正值 机器人输:负值 ChessRank []int32 RealCtrl bool CycleID string } func NewScene(args *CreateSceneParam) *Scene { gameId := int(args.GetGameId()) gameMode := int(args.GetGameMode()) sp := GetScenePolicy(gameId, gameMode) if sp == nil { logger.Logger.Errorf("Game id %v not register in ScenePolicyPool.", gameId) return nil } tNow := time.Now() s := &Scene{ WGCreateScene: args.WGCreateScene, ws: args.Session, Players: make(map[int32]*Player), audiences: make(map[int32]*Player), sp: sp, GameStartTime: tNow, inviteInterval: model.GameParamData.RobotInviteInitInterval, bEnterAfterStart: args.GetEnterAfterStart(), ChessRank: args.GetChessRank(), KeyGameId: strconv.Itoa(int(args.GetGameId())), KeyGamefreeId: strconv.Itoa(int(args.GetDBGameFree().GetId())), KeyGameDif: args.GetDBGameFree().GetGameDif(), } s.CycleID, _ = model.AutoIncGameLogId() s.init() return s } func (this *Scene) GetSceneType() int32 { if this.GetDBGameFree() != nil { return this.GetDBGameFree().GetSceneType() } return 0 } func (this *Scene) RebindPlayerSnId(oldSnId, newSnId int32) { if p, exist := this.Players[oldSnId]; exist { delete(this.Players, oldSnId) this.Players[newSnId] = p } if p, exist := this.audiences[oldSnId]; exist { delete(this.audiences, oldSnId) this.audiences[newSnId] = p } if rebind, ok := this.ExtraData.(CanRebindSnId); ok { rebind.RebindPlayerSnId(oldSnId, newSnId) } } func (this *Scene) GetInit() bool { return this.init() } func (this *Scene) init() bool { tNow := time.Now() sceneRandSeed++ this.Rand = rand.New(rand.NewSource(sceneRandSeed)) this.nextInviteTime = tNow.Add(time.Second * time.Duration(this.Rand.Int63n(model.GameParamData.RobotInviteInitInterval))) this.RandRobotCnt() return true } func (this *Scene) GetParam(idx int) int64 { if idx < 0 || idx >= len(this.Params) { return -1 } return this.Params[idx] } func (this *Scene) GetBetMap() []int64 { return this.GetDBGameFree().GetOtherIntParams() } func (this *Scene) GetGameFreeId() int32 { return this.GetDBGameFree().GetId() } func (this *Scene) GetKeyGameId() string { return this.KeyGameId } func (this *Scene) SetKeyGameId(keyGameId string) { this.KeyGameId = keyGameId } func (this *Scene) GetSceneId() int { return int(this.SceneId) } func (this *Scene) SetSceneId(sceneId int) { this.SceneId = int32(sceneId) } func (this *Scene) GetGroupId() int32 { return this.GroupId } func (this *Scene) SetGroupId(groupId int32) { this.GroupId = groupId } func (this *Scene) GetExtraData() interface{} { return this.ExtraData } func (this *Scene) SetExtraData(data interface{}) { this.ExtraData = data } func (this *Scene) GetSceneState() SceneState { return this.SceneState } func (this *Scene) SetSceneState(state SceneState) { this.SceneState = state } func (this *Scene) GetGameId() int { return int(this.GameId) } func (this *Scene) SetGameId(gameId int) { this.GameId = int32(gameId) } func (this *Scene) GetPlayerNum() int { return int(this.WGCreateScene.GetPlayerNum()) } func (this *Scene) SetPlayerNum(playerNum int) { this.PlayerNum = int32(playerNum) } func (this *Scene) GetGameMode() int { return int(this.GameMode) } func (this *Scene) SetGameMode(gameMode int) { this.GameMode = int32(gameMode) } func (this *Scene) GetGaming() bool { return this.Gaming } func (this *Scene) SetGaming(gaming bool) { this.Gaming = gaming } func (this *Scene) GetTesting() bool { return this.Testing } func (this *Scene) SetTesting(testing bool) { this.Testing = testing } func (this *Scene) GetCreator() int32 { return this.Creator } func (this *Scene) SetCreator(creator int32) { this.Creator = creator } func (this *Scene) GetSceneMode() int { return int(this.SceneMode) } func (this *Scene) SetSceneMode(sceneMode int) { this.SceneMode = int32(sceneMode) } func (this *Scene) GetParams() []int64 { return this.Params } func (this *Scene) GetStateStartTime() time.Time { return this.StateStartTime } func (this *Scene) SetStateStartTime(stateStartTime time.Time) { this.StateStartTime = stateStartTime } func (this *Scene) GetGameStartTime() time.Time { return this.GameStartTime } func (this *Scene) SetGameStartTime(gameStartTime time.Time) { this.GameStartTime = gameStartTime } func (this *Scene) GetGameNowTime() time.Time { return this.GameNowTime } func (this *Scene) SetGameNowTime(gameNowTime time.Time) { this.GameNowTime = gameNowTime } func (this *Scene) GetNumOfGames() int { return this.NumOfGames } func (this *Scene) SetNumOfGames(numOfGames int) { this.NumOfGames = numOfGames } func (this *Scene) GetCpCtx() model.CoinPoolCtx { return this.CpCtx } func (this *Scene) SetCpCtx(cpCtx model.CoinPoolCtx) { this.CpCtx = cpCtx } func (this *Scene) GetAudiences() map[int32]*Player { return this.audiences } func (this *Scene) GetDisbandGen() int { return this.disbandGen } func (this *Scene) SetDisbandGen(disbandGen int) { this.disbandGen = disbandGen } func (this *Scene) GetScenePolicy() ScenePolicy { return this.sp } func (this *Scene) SetScenePolicy(sp ScenePolicy) { this.sp = sp } func (this *Scene) GetGraceDestroy() bool { return this.graceDestroy } func (this *Scene) SetGraceDestroy(graceDestroy bool) { this.graceDestroy = graceDestroy } func (this *Scene) GetCpControlled() bool { return this.CpControlled } func (this *Scene) SetCpControlled(cpControlled bool) { this.CpControlled = cpControlled } func (this *Scene) GetSystemCoinOut() int64 { return this.SystemCoinOut } func (this *Scene) SetSystemCoinOut(systemCoinOut int64) { this.SystemCoinOut = systemCoinOut } func (this *Scene) GetBEnterAfterStart() bool { return this.bEnterAfterStart } func (this *Scene) SetBEnterAfterStart(bEnterAfterStart bool) { this.bEnterAfterStart = bEnterAfterStart } func (this *Scene) GetTimerRandomRobot() int64 { return this.timerRandomRobot } func (this *Scene) SetTimerRandomRobot(timerRandomRobot int64) { this.timerRandomRobot = timerRandomRobot } func (this *Scene) GetDestroyed() bool { return this.destroyed } func (this *Scene) SetDestroyed(destroyed bool) { this.destroyed = destroyed } // //////////////////////////////////////////////// func (this *Scene) OnStart() { logger.Logger.Trace("Scene on start.") this.sp.OnStart(this) this.TryInviteRobot() } func (this *Scene) OnStop() { logger.Logger.Trace("Scene on stop.") this.sp.OnStop(this) } func (this *Scene) OnTick() { if !this.pause { this.TryInviteRobot() this.sp.OnTick(this) } } func (this *Scene) SendRoomType(p *Player) { //通知客户端 当前房间类型 //RoomSign := &protocol.SCClubRoomSign{ // ClubId: proto.Int64(this.ClubId), //} //proto.SetDefaults(RoomSign) //logger.Logger.Trace("RoomSign: ", RoomSign) //p.SendToClient(int(protocol.MmoPacketID_PACKET_SC_CLUB_ROOMSIGN), RoomSign) } ////////////////////////////////////////////////// func (this *Scene) PlayerEnter(p *Player, isLoaded bool) { logger.Logger.Trace("(this *Scene) PlayerEnter:", p.SnId, isLoaded, this.SceneId, p.GetName()) this.Players[p.SnId] = p p.scene = this pack := &gamehall.SCEnterRoom{ GameId: this.GameId, ModeType: this.GameMode, RoomId: this.SceneId, OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game, Params: []int32{}, ClubId: proto.Int32(this.ClubId), } proto.SetDefaults(pack) p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_ENTERROOM), pack) if p.IsRob { this.robotNum++ logger.Logger.Tracef("(this *Scene) PlayerEnter(%v) robot(%v) robotlimit(%v)", this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, this.robotLimit) } else { p.Trusteeship = 0 p.ValidCacheBetTotal = 0 this.realPlayerNum++ this.RandRobotCnt() } p.OnEnter(this) p.SyncFlagToWorld() if !isLoaded && !p.IsRob { //等待玩家加载 p.MarkFlag(PlayerState_Leave) } //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnPlayerEnter(this, p) }) if p.WBLevel < 0 { WarningBlackPlayer(p.SnId, this.GetDBGameFree().Id) } this.ResetNextInviteTime() } func (this *Scene) PlayerLeave(p *Player, reason int, isBill bool) { logger.Logger.Trace("===(this *Scene) PlayerLeave ", p.SnId, reason, isBill) //logger.Logger.Trace(utils.GetCallStack()) if _, exist := this.Players[p.SnId]; !exist { logger.Logger.Warnf("(this *Scene) PlayerLeave(%v) no found in scene(%v)", p.SnId, this.SceneId) return } //当前状态不能离场 if !this.CanChangeCoinScene(p) && !this.destroyed { pack := &gamehall.SCLeaveRoom{ //OpRetCode: p.opCode, //protocol.OpResultCode_OPRC_Hundred_YouHadBetCannotLeave, OpRetCode: gamehall.OpResultCode_Game(p.OpCode), RoomId: this.SceneId, } if pack.GetOpRetCode() == gamehall.OpResultCode_Game_OPRC_Sucess_Game { //不能这么做,机器人有特殊判定 //pack.OpRetCode = gamehall.OpResultCode_OPRC_Error pack.OpRetCode = gamehall.OpResultCode_Game_OPRC_Error_Game } proto.SetDefaults(pack) p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_LEAVEROOM), pack) logger.Logger.Tracef("(this *Scene) Cant PlayerLeave(%v) no found in scene(%v)", p.SnId, this.SceneId) return } //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnPlayerLeave(this, p, reason) }) p.OnLeave(reason) delete(this.Players, p.SnId) isBill = true //send world离开房间 pack := &server.GWPlayerLeave{ RoomId: this.SceneId, PlayerId: proto.Int32(p.SnId), Reason: proto.Int(reason), ServiceFee: proto.Int64(p.serviceFee), GameTimes: proto.Int32(p.GameTimes), BetCoin: proto.Int64(p.TotalBet), WinTimes: proto.Int(p.winTimes), LostTimes: proto.Int(p.lostTimes), TotalConvertibleFlow: proto.Int64(p.TotalConvertibleFlow), ValidCacheBetTotal: proto.Int64(p.ValidCacheBetTotal), MatchId: this.GetMatch().GetMatchSortId(), CurIsWin: proto.Int64(p.CurIsWin), // 负数:输 0:平局 正数:赢 } matchRobotGrades := p.MatchRobotGrades if matchRobotGrades != nil { pack.MatchRobotGrades = make(map[int32]int32) for _, gradeInfo := range matchRobotGrades { pack.MatchRobotGrades[gradeInfo.CopySnid] = proto.Int32(gradeInfo.Grade) } p.MatchRobotGrades = nil } pack.ReturnCoin = proto.Int64(p.Coin) if this.Testing { pack.ReturnCoin = proto.Int64(p.takeCoin) } pack.GameCoinTs = proto.Int64(p.GameCoinTs) if !p.IsLocal { data, err := p.MarshalData(int(this.GameId)) if err == nil { pack.PlayerData = data } } //pack.Items = make(map[int32]int64) //for id, num := range p.Items { // pack.Items[id] = num //} pack.RankScore = make(map[int32]int64) for k, v := range p.RankScore { pack.RankScore[k] = v } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERLEAVE), pack) logger.Logger.Tracef("(this *Scene) PlayerLeave(%v) success reason %v", p.SnId, reason) if p.IsRob { this.robotNum-- if this.robotNum != len(this.Players) { var num int for _, p2 := range this.Players { if p2.IsRob { num++ } } this.robotNum = num } logger.Logger.Tracef("(this *Scene) PlayerLeave(%v) robot(%v) robotlimit(%v)", this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, this.robotLimit) } else { this.realPlayerNum-- this.RandRobotCnt() } this.ResetNextInviteTime() } func (this *Scene) AudienceEnter(p *Player, isload bool) { logger.Logger.Trace("(this *Scene) AudienceEnter") this.audiences[p.SnId] = p p.scene = this p.MarkFlag(PlayerState_Audience) pack := &gamehall.SCEnterRoom{ GameId: this.GameId, ModeType: this.GameMode, RoomId: this.SceneId, OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game, } proto.SetDefaults(pack) p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_ENTERROOM), pack) p.OnAudienceEnter(this) if !isload && !p.IsRob { p.MarkFlag(PlayerState_Leave) } //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) }) } func (this *Scene) AudienceLeave(p *Player, reason int) { logger.Logger.Trace("(this *Scene) AudienceLeave") //当前状态不能离场 if !this.CanChangeCoinScene(p) { pack := &gamehall.SCLeaveRoom{ OpRetCode: gamehall.OpResultCode_Game(p.OpCode), //protocol.OpResultCode_OPRC_Hundred_YouHadBetCannotLeave, RoomId: this.SceneId, } proto.SetDefaults(pack) p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_LEAVEROOM), pack) return } //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceLeave(this, p, reason) }) p.OnAudienceLeave(reason) delete(this.audiences, p.SnId) //send world离开房间 pack := &server.GWPlayerLeave{ RoomId: this.SceneId, PlayerId: proto.Int32(p.SnId), Reason: proto.Int(reason), TotalConvertibleFlow: proto.Int64(p.TotalConvertibleFlow), ValidCacheBetTotal: proto.Int64(p.ValidCacheBetTotal), } pack.ReturnCoin = proto.Int64(p.Coin) if this.Testing { pack.ReturnCoin = proto.Int64(p.takeCoin) } pack.GameCoinTs = proto.Int64(p.GameCoinTs) // if p.dirty { // data, err := p.MarshalData(this.gameId) // if err == nil { // pack.PlayerData = data // } // } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_AUDIENCELEAVE), pack) } func (this *Scene) AudienceSit(p *Player) { logger.Logger.Trace("(this *Scene) AudienceSit") if _, exist := this.audiences[p.SnId]; exist { delete(this.audiences, p.SnId) this.Players[p.SnId] = p p.scene = this p.OnEnter(this) //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceSit(this, p) }) } } func (this *Scene) HasPlayer(p *Player) bool { if p == nil { return false } if pp, ok := this.Players[p.SnId]; ok && pp == p { return true } return false } func (this *Scene) HasAudience(p *Player) bool { if p == nil { return false } if pp, ok := this.audiences[p.SnId]; ok && pp == p { return true } return false } func (this *Scene) GetPlayer(id int32) *Player { if p, exist := this.Players[id]; exist { return p } return nil } func (this *Scene) GetPlayerByPos(pos int) *Player { for _, p := range this.Players { if p.Pos == pos { return p } } return nil } func (this *Scene) PlayerDropLine(snid int32) { logger.Logger.Trace("(this *Scene) PlayerDropLine") if p, exist := this.Players[snid]; exist { p.OnDropLine() //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnPlayerDropLine(this, p) }) } else if p, exist := this.audiences[snid]; exist { p.OnAudienceDropLine() //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceDropLine(this, p) }) } } func (this *Scene) PlayerRehold(snid int32, sid int64, gs *netlib.Session) { logger.Logger.Trace("(this *Scene) PlayerRehold") if p, exist := this.Players[snid]; exist { p.OnRehold(sid, gs) //if !p.IsRob { // p.trusteeship = 0 //} //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnPlayerRehold(this, p) }) } else if p, exist := this.audiences[snid]; exist { p.OnRehold(sid, gs) //if !p.IsRob { // p.trusteeship = 0 //} //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) }) } } func (this *Scene) PlayerReturn(p *Player, isLoaded bool) { logger.Logger.Trace("(this *Scene) PlayerReturn") pack := &gamehall.SCReturnRoom{ RoomId: this.SceneId, GameId: this.GameId, ModeType: this.GameMode, Params: common.CopySliceInt64ToInt32(this.Params), HallId: this.GetDBGameFree().GetId(), IsLoaded: proto.Bool(isLoaded), OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game, ClubId: proto.Int32(this.ClubId), } proto.SetDefaults(pack) p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_RETURNROOM), pack) logger.Logger.Tracef("Scene.PlayerReturn %v", pack) //if !p.IsRob { // p.trusteeship = 0 //} if this.HasPlayer(p) { //避免游戏接口异常 //utils.RunPanicless(func() { this.sp.OnPlayerRehold(this, p) }) //这里应该调用 return消息 因为在上面rehold的消息已经处理过了 utils.RunPanicless(func() { this.sp.OnPlayerReturn(this, p) }) } else if this.HasAudience(p) { //避免游戏接口异常 utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) }) } if !p.IsRob { //等待玩家加载 if isLoaded { p.UnmarkFlag(PlayerState_Leave) } else { p.MarkFlag(PlayerState_Leave) } } if this.IsMatchScene() { p.SetIParam(common.PlayerIParam_IsQuit, 0) p.UnmarkFlag(PlayerState_MatchQuit) } } // 广播消息 func (this *Scene) Broadcast(packetid int, msg rawproto.Message, excludeSid int64, includeOffline ...bool) { excludePos := -1 mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion) for _, p := range this.Players { if p != nil { if p.sid != excludeSid { if (p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave)) || len(includeOffline) != 0 { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.sid), }, }) } } if p.sid == excludeSid { excludePos = p.Pos } } } for _, p := range this.audiences { if p != nil && p.sid != excludeSid { if (p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave)) || len(includeOffline) != 0 { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.sid), }, }) } } } if this.rr != nil && !this.Testing && this.Gaming && !this.IsHundredScene() && !this.IsMatchScene() { this.rr.Record(-1, excludePos, packetid, msg) } for gateSess, v := range mgs { if gateSess != nil && len(v) != 0 { pack, err := common.CreateMulticastPacket(packetid, msg, v...) if err == nil { proto.SetDefaults(pack) gateSess.Send(int(srvlibproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack) } } } } func (this *Scene) RobotBroadcast(packetid int, msg rawproto.Message) { mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion) for _, p := range this.Players { if p != nil && p.IsRob { if p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave) { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.sid), }, }) } } } for gateSess, v := range mgs { if gateSess != nil && len(v) != 0 { pack, err := common.CreateMulticastPacket(packetid, msg, v...) if err == nil { proto.SetDefaults(pack) gateSess.Send(int(srvlibproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack) } } } } func (this *Scene) BroadcastToAudience(packetid int, msg rawproto.Message) { if len(this.audiences) > 0 { mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion) for _, p := range this.audiences { if p != nil { if p.gateSess != nil && p.IsOnLine() { mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.sid), }, }) } } } for gateSess, v := range mgs { if gateSess != nil && len(v) != 0 { pack, err := common.CreateMulticastPacket(packetid, msg, v...) if err == nil { proto.SetDefaults(pack) gateSess.Send(int(srvlibproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack) } } } } } func (this *Scene) GetAudiencesNum() int { if this.audiences != nil { return len(this.audiences) } return 0 } func (this *Scene) ChangeSceneState(stateid int) { if this.destroyed { return } state := this.sp.GetSceneState(this, stateid) if state == nil { return } oldState := -1 if this.SceneState != nil { oldState = this.SceneState.GetState() if this.SceneState.CanChangeTo(state) { logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState %v -> %v", this.SceneId, this.SceneState.GetState(), state.GetState()) this.SceneState.OnLeave(this) this.SceneState = state this.SceneState.OnEnter(this) this.sp.NotifyGameState(this) } else { logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState failed %v -> %v", this.SceneId, this.SceneState.GetState(), state.GetState()) } } else { logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState -> %v", this.SceneId, state.GetState()) this.SceneState = state this.SceneState.OnEnter(this) //this.SyncSceneState(stateid) } if this.aiMgr != nil { this.aiMgr.OnChangeState(this, oldState, stateid) } } func (this *Scene) SendToWorld(packetid int, pack interface{}) { if this.ws != nil { this.ws.Send(packetid, pack) } } func (this *Scene) FirePlayerEvent(p *Player, evtcode int, params []int64) { if this.SceneState != nil { this.SceneState.OnPlayerEvent(this, p, evtcode, params) } ////比赛事件 //if this.mp != nil { // this.mp.OnPlayerEvent(this, p, evtcode, params) //} } func (this *Scene) Pause() { this.pause = true } // RankMatchDestroy 排位解散房间 func (this *Scene) RankMatchDestroy() { if this.IsRankMatch() { this.Destroy(true) } } func (this *Scene) Destroy(force bool) { this.destroyed = true this.pause = true if !this.IsMatchScene() { for _, p := range this.Players { this.PlayerLeave(p, common.PlayerLeaveReason_OnDestroy, true) } for _, p := range this.audiences { this.AudienceLeave(p, common.PlayerLeaveReason_OnDestroy) } } else { for _, p := range this.Players { this.PlayerLeave(p, common.PlayerLeaveReason_OnBilled, true) } } for _, p := range this.Players { PlayerMgrSington.DelPlayerBySnId(p.SnId) } for _, p := range this.audiences { PlayerMgrSington.DelPlayerBySnId(p.SnId) } isCompleted := this.sp.IsCompleted(this) || this.completed SceneMgrSington.DestroyScene(int(this.SceneId)) pack := &server.GWDestroyScene{ SceneId: int64(this.SceneId), IsCompleted: isCompleted, } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_DESTROYSCENE), pack) logger.Logger.Trace("(this *Scene) Destroy(force bool) isCompleted", isCompleted) } func (this *Scene) IsPrivateScene() bool { return this.SceneId >= common.PrivateSceneStartId && this.SceneId <= common.PrivateSceneMaxId || this.SceneMode == common.SceneMode_Private } // IsFreePublic 自由桌 func (this *Scene) IsFreePublic() bool { return this.GetDBGameFree().GetFreeMode() == 1 } // IsRankMatch 排位赛 func (this *Scene) IsRankMatch() bool { return this.GetDBGameFree().GetRankType() > 0 } // IsMatchScene 比赛场 func (this *Scene) IsMatchScene() bool { return this.SceneId >= common.MatchSceneStartId && this.SceneId <= common.MatchSceneMaxId } func (this *Scene) IsCustom() bool { return this.GetDBGameFree().GetIsCustom() > 0 } func (this *Scene) IsFull() bool { return len(this.Players) >= this.GetPlayerNum() } // 大厅场 func (this *Scene) IsHallScene() bool { return this.SceneId >= common.HallSceneStartId && this.SceneId <= common.HallSceneMaxId } // 金豆自由场 func (this *Scene) IsCoinScene() bool { return this.SceneId >= common.CoinSceneStartId && this.SceneId <= common.CoinSceneMaxId } // 百人场 func (this *Scene) IsHundredScene() bool { return this.SceneId >= common.HundredSceneStartId && this.SceneId <= common.HundredSceneMaxId } func (this *Scene) GetCoinSceneLowerThanKick() int64 { if this.GetDBGameFree() != nil { return this.GetDBGameFree().GetLowerThanKick() } return 0 } func (this *Scene) GetCoinSceneMaxCoinLimit() int64 { if this.GetDBGameFree() != nil { return this.GetDBGameFree().GetMaxCoinLimit() } return 0 } // CoinInLimitLocal 本地游戏入场限额检查 func (this *Scene) CoinInLimitLocal(coin int64) bool { minCoin := this.GetLimitCoin() if minCoin != 0 && coin < minCoin { return false } if coin <= 0 { return false } return true } // NotCoinInLimitType 金额超出入场限额,返回踢出类型 func (this *Scene) NotCoinInLimitType(coin int64) int { if common.IsLocalGame(int(this.GameId)) { minCoin := this.GetLimitCoin() if minCoin != 0 && coin < minCoin { return common.PlayerLeaveReason_Bekickout } if coin <= 0 { return common.PlayerLeaveReason_Bekickout } return common.PlayerLeaveReason_Normal } minCoin := int(this.GetCoinSceneLowerThanKick()) maxCoin := int(this.GetCoinSceneMaxCoinLimit()) if minCoin != 0 && coin < int64(minCoin) { return common.PlayerLeaveReason_Bekickout } if maxCoin != 0 && coin > int64(maxCoin) { return common.PlayerLeaveReason_RoomMaxCoin } if coin <= 0 { return common.PlayerLeaveReason_Bekickout } return common.PlayerLeaveReason_Normal } // CoinInLimit 单入场限额检查 func (this *Scene) CoinInLimit(coin int64) bool { if common.IsLocalGame(int(this.GameId)) { return this.CoinInLimitLocal(coin) } minCoin := int(this.GetCoinSceneLowerThanKick()) maxCoin := int(this.GetCoinSceneMaxCoinLimit()) if minCoin != 0 && coin < int64(minCoin) { return false } if maxCoin != 0 && coin > int64(maxCoin) { return false } if coin <= 0 { return false } return true } // 根据底注去取createroom表里面的最小携带金额 func (this *Scene) GetLimitCoin() int64 { limitCoin := int64(0) tmpIds := []int32{} for _, data := range srvdata.PBDB_CreateroomMgr.Datas.GetArr() { if data.GameId == this.GameId && data.GameSite == this.GetDBGameFree().GetSceneType() { betRange := data.GetBetRange() if len(betRange) == 0 { continue } for j := 0; j < len(betRange); j++ { if betRange[j] == this.BaseScore && len(data.GetGoldRange()) > 0 && data.GetGoldRange()[0] != 0 { tmpIds = append(tmpIds, data.GetId()) break } } } } if len(tmpIds) > 0 { goldRange := srvdata.PBDB_CreateroomMgr.GetData(tmpIds[0]).GetGoldRange() if len(goldRange) != 0 && goldRange[0] != 0 { limitCoin = int64(goldRange[0]) } if limitCoin != 0 { for _, id := range tmpIds { tmp := srvdata.PBDB_CreateroomMgr.GetData(id).GetGoldRange() if int64(tmp[0]) < limitCoin && tmp[0] != 0 { limitCoin = int64(tmp[0]) } } } } return limitCoin } func (this *Scene) CoinOverMaxLimit(coin int64, p *Player) bool { if this.Testing { return false } if coin < 0 { return false } if p.ExpectLeaveCoin != 0 && this.IsCoinScene() { //暂只对对战场生效 if p.ExpectLeaveCoin < p.takeCoin { //期望输的时候离场 if coin <= p.ExpectLeaveCoin { return true } } else { //期望赢的时候离场 if coin >= p.ExpectLeaveCoin { return true } } } else { if this.GetDBGameFree() != nil { limit := this.GetDBGameFree().GetRobotLimitCoin() if len(limit) >= 2 { comp := common.RandInt(int(limit[0]), int(limit[1])) if coin > int64(comp) { return true } } } } return false } func (this *Scene) CorrectBillCoin(coin, limit1, limit2 int64) int64 { if coin > limit1 { coin = limit1 } if coin > limit2 { coin = limit2 } return coin } func (this *Scene) GetCoinSceneServiceFee() int32 { if this.GetDBGameFree() != nil { return this.GetDBGameFree().GetServiceFee() } return 0 } func (this *Scene) GetCoinSceneTypeId() int32 { if this.GetDBGameFree() != nil { return this.GetDBGameFree().Id } return 0 } func (this *Scene) GetCoinSceneName() string { if this.GetDBGameFree() != nil { return this.GetDBGameFree().GetName() + this.GetDBGameFree().GetTitle() } return "" } func (this *Scene) GetHundredSceneName() string { if this.IsHundredScene() && this.GetDBGameFree() != nil { if this.GetDBGameFree().GetName() == this.GetDBGameFree().GetTitle() { return this.GetDBGameFree().GetTitle() } else { return this.GetDBGameFree().GetName() + this.GetDBGameFree().GetTitle() } } return "" } func (this *Scene) GetSceneName() string { if this.IsCoinScene() { return this.GetCoinSceneName() } else if this.IsHundredScene() { return this.GetHundredSceneName() } return "" } func (this *Scene) CanChangeCoinScene(p *Player) bool { //if p.IsMarkFlag(PlayerState_Audience) { // if this.drp != nil { // return this.drp.CanChangeCoinScene(this, p) // } //} //if this.mp != nil { // if !this.mp.IsMatchEnd(this) { // return false // } //} if this.sp != nil { return this.sp.CanChangeCoinScene(this, p) } return false } func (this *Scene) SyncPlayerCoin() { //if this.Testing { // return //} //pack := &server.GWSyncPlayerCoin{ // SceneId: proto.Int(this.SceneId), //} //switch this.GameId { //case common.GameId_HFishing, common.GameId_TFishing: // for _, value := range this.Players { // if value.IsRob { // continue // } // //todo dev 捕鱼的逻辑暂时不用 开发的时候再增加 // //if exData, ok := value.extraData.(*FishingPlayerData); ok { // // if exData.CoinCache != value.LastSyncCoin { // // pack.PlayerCoins = append(pack.PlayerCoins, int64(value.SnId)) // // pack.PlayerCoins = append(pack.PlayerCoins, exData.CoinCache) // // value.LastSyncCoin = exData.CoinCache // // } // //} // } //default: // for _, value := range this.Players { // if value.Coin != value.LastSyncCoin && !value.IsRob { // pack.PlayerCoins = append(pack.PlayerCoins, int64(value.SnId)) // pack.PlayerCoins = append(pack.PlayerCoins, value.Coin) // value.LastSyncCoin = value.Coin // } // } //} //if len(pack.PlayerCoins) > 0 { // proto.SetDefaults(pack) // this.SendToWorld(int(server.SSPacketID_PACKET_GW_SYNCPLAYERCOIN), pack) //} } func (this *Scene) SyncSceneState(state int) { pack := &server.GWSceneState{ RoomId: int32(this.SceneId), RoomState: int32(state), } this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTATE), pack) } func (this *Scene) NotifySceneRoundStart(round int) { pack := &server.GWSceneStart{ RoomId: this.SceneId, CurrRound: proto.Int(round), Start: proto.Bool(true), MaxRound: this.TotalOfGames, } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTART), pack) } func (this *Scene) NotifySceneRoundPause() { pack := &server.GWSceneStart{ RoomId: this.SceneId, Start: proto.Bool(false), CurrRound: proto.Int(this.NumOfGames), MaxRound: this.TotalOfGames, } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTART), pack) } func (this *Scene) SyncGameState(sec, bl int) { if this.SceneState != nil { pack := &server.GWGameState{ SceneId: this.SceneId, State: proto.Int(this.SceneState.GetState()), Ts: proto.Int64(time.Now().Unix()), Sec: proto.Int(sec), BankerListNum: proto.Int(bl), } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_GAMESTATE), pack) } } // SyncScenePlayer 游戏开始的时候同步防伙牌数据 func (this *Scene) SyncScenePlayer() { pack := &server.GWScenePlayerLog{ GameId: this.GameId, GameFreeId: proto.Int32(this.GetDBGameFree().GetId()), } for _, value := range this.Players { if value.IsRob || !value.IsGameing() { continue } pack.Snids = append(pack.Snids, value.SnId) } this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEPLAYERLOG), pack) } func (this *Scene) RecordReplayStart() { if !this.IsHundredScene() && !this.IsMatchScene() { logger.Logger.Trace("RecordReplayStart-----", this.GetReplayCode(), this.NumOfGames, this.replayAddId) id := fmt.Sprintf("%d%d%v%d", this.GameId, this.SceneId, this.GameNowTime.Format(ReplayIdTf), this.replayAddId) this.rr = NewReplayRecorder(id) } } func (this *Scene) RecordReplayOver() { if !this.Testing && !this.IsHundredScene() && !this.IsMatchScene() { logger.Logger.Trace("RecordReplayOver-----", this.GetReplayCode(), this.NumOfGames, this.replayAddId) this.replayAddId++ this.rr.Fini(this) this.RecordReplayStart() } } // TryDismissRob 尝试机器人离场 func (this *Scene) TryDismissRob(params ...int) { if this.IsMatchScene() { return } if this.IsCoinScene() { allRobot := true for _, p := range this.Players { if !p.IsRob { allRobot = false break } } //一次离开一个 hasLeave := false if allRobot && !this.IsPreCreateScene() { for _, p := range this.Players { if p.IsRob { this.PlayerLeave(p, common.PlayerLeaveReason_Normal, true) hasLeave = true } } } //当局已经检查过了 if this.nogDismiss == this.NumOfGames { return } this.nogDismiss = this.NumOfGames //如果是满桌并且是禁止匹配真人,那么保持满桌几局 if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Forbid && this.IsFull() && rand.Intn(4) == 1 { hasLeave = true } if !hasLeave && !this.Testing { for _, p := range this.Players { rands := this.Rand.Int63n(20) + 20 a := float64(p.Coin) / float64(p.takeCoin) if p != nil && p.IsRob && a >= float64(rands)/10 { this.PlayerLeave(p, common.PlayerLeaveReason_Normal, true) hasLeave = true break } } } if !hasLeave && this.GetDBGameFree().GetMatchTrueMan() != common.MatchTrueMan_Forbid && len(params) > 0 && params[0] == 1 && this.IsFull() && common.RandInt(10000) < 4000 { for _, r := range this.Players { if r.IsRob { this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true) hasLeave = true break } } } if !hasLeave { for _, r := range this.Players { if r.IsRob { if !r.IsGameing() { //5%的概率,不玩游戏直接离场 if rand.Intn(100) < 5 { this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true) hasLeave = true break } } else { //玩游戏的,玩几局有概率离场 expectTimes := 5 + rand.Int31n(20) if r.GameTimes >= expectTimes { this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true) hasLeave = true break } } } } } //如果当局有机器人离开,适当延长下下次邀请的时间 if hasLeave { tNow := time.Now() if this.nextInviteTime.Sub(tNow) < time.Second { this.nextInviteTime = tNow.Add(time.Second * time.Duration(rand.Int31n(3)+1)) } } } } func (this *Scene) CreateGameRecPacket() *server.GWGameRec { return &server.GWGameRec{ RoomId: this.SceneId, NumOfGames: proto.Int(this.NumOfGames), GameTime: proto.Int(int(time.Now().Sub(this.GameStartTime) / time.Second)), } } func (this *Scene) IsAllReady() bool { for _, p := range this.Players { if !p.IsOnLine() || !p.IsReady() { return false } } return true } func (this *Scene) GetOnlineCnt() int { cnt := 0 for _, p := range this.Players { if p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave) { cnt++ } } return cnt } func (this *Scene) GetRealPlayerCnt() int { cnt := 0 for _, p := range this.Players { if !p.IsRob { cnt++ } } return cnt } func (this *Scene) GetGameingPlayerCnt() int { cnt := 0 for _, p := range this.Players { if p != nil && p.IsGameing() { cnt += 1 } } return cnt } func (this *Scene) GetGameingRealPlayerCnt() int { cnt := 0 for _, p := range this.Players { if p != nil && p.IsGameing() && !p.IsRob { cnt += 1 } } return cnt } func (this *Scene) GetRandomRobotPlayer() *Player { robotArray := []*Player{} for _, p := range this.Players { if p != nil && p.IsGameing() && p.IsRob { robotArray = append(robotArray, p) } } if len(robotArray) > 0 { return robotArray[common.RandInt(0, len(robotArray))] } return nil } func (this *Scene) CoinPoolCanOut() bool { return true /* 暂时屏蔽 noRobotPlayerCount := this.GetRealPlayerCnt() setting := coinPoolMgr.GetCoinPoolSetting(this.platform, this.gamefreeId, this.groupId) if setting != nil { return int32(noRobotPlayerCount) >= setting.GetMinOutPlayerNum() } return int32(noRobotPlayerCount) >= this.GetDBGameFree().GetMinOutPlayerNum() */ } func (this *Scene) ClearAutoPlayer() { for _, p := range this.Players { if p.IsAuto() { p.UnmarkFlag(PlayerState_Auto) p.SyncFlag() } } } type GameDetailedParam struct { Trend20Lately string //最近20局开奖结果 CtrlType int PlayerPool map[int]int } // 保存详细游戏日志 func (this *Scene) SaveGameDetailedLog(logid string, gamedetailednote string, gameDetailedParam *GameDetailedParam) { if this != nil { if !this.Testing { //测试场屏蔽掉 trend20Lately := gameDetailedParam.Trend20Lately baseScore := this.GetDBGameFree().GetBaseScore() if common.IsLocalGame(int(this.GameId)) { baseScore = this.BaseScore } if this.IsCoinScene() { mapPlatform := make(map[string]bool) for _, p := range this.Players { if _, ok := mapPlatform[p.Platform]; !ok { mapPlatform[p.Platform] = true log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, gamedetailednote, p.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool) if log != nil { if this.IsMatchScene() { log.MatchId = this.GetMatch().GetMatchSortId() } if this.IsCustom() { log.CycleId = this.CycleID } LogChannelSingleton.WriteLog(log) } } } } else { log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, gamedetailednote, this.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool) if log != nil { if this.IsMatchScene() { log.MatchId = this.GetMatch().GetMatchSortId() } if this.IsCustom() { log.CycleId = this.CycleID } newLog := new(model.GameDetailedLog) *newLog = *log LogChannelSingleton.WriteLog(log) } } } } } type SaveGamePlayerListLogParam struct { Platform string //平台 Channel string //渠道 Promoter string //推广员 PackageTag string //包标识 InviterId int32 //邀请人 LogId string //日志id TotalIn int64 //总投入 TotalOut int64 //总产出 TaxCoin int64 //总税收 ClubPumpCoin int64 //俱乐部抽水 BetAmount int64 //下注量 WinAmountNoAnyTax int64 //税后赢取额(净利润,正负值) ValidBet int64 //有效下注 ValidFlow int64 //有效流水 IsFirstGame bool //是否第一次游戏 IsLeave bool //是否中途离开,用于金花,德州可以中途离开游戏使用 IsFree bool //拉霸专用 是否免费 WinSmallGame int64 //拉霸专用 小游戏奖励 WinTotal int64 //拉霸专用 本局输赢 PlayerName string //玩家名字 } func GetSaveGamePlayerListLogParam(platform, channel, promoter, packageTag, logid string, inviterId int32, totalin, totalout, taxCoin, clubPumpCoin, betAmount, winAmountNoAnyTax, validBet, validFlow int64, isFirstGame, isLeave bool) *SaveGamePlayerListLogParam { return &SaveGamePlayerListLogParam{ Platform: platform, Channel: channel, Promoter: promoter, PackageTag: packageTag, InviterId: inviterId, LogId: logid, TotalIn: totalin, TotalOut: totalout, TaxCoin: taxCoin, ClubPumpCoin: clubPumpCoin, BetAmount: betAmount, WinAmountNoAnyTax: winAmountNoAnyTax, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: isFirstGame, IsLeave: isLeave, } } func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, baseScore int32) { if this.SceneMode == common.SceneMode_Private { return } log := model.NewFriendRecordLogEx(this.Platform, snid, isWin, this.GameId, baseScore, billCoin, int64(this.GetMatch().GetMatchType())) if log != nil { LogChannelSingleton.WriteLog(log) } } // 保存玩家和GameDetailedLog的映射表 func (this *Scene) SaveGamePlayerListLog(snid int32, param *SaveGamePlayerListLogParam) { if this != nil { if !this.Testing { //测试场屏蔽掉 龙虎两边都压,totalin和totalout都=0,这个条件去掉 //统计流水值 playerEx := this.GetPlayer(snid) //有些结算的时候,玩家已经退场,不要用是否在游戏,0709,修改为扣税后数值 if playerEx != nil && !param.IsLeave && !playerEx.IsRob && (param.IsFree || param.TotalIn != 0 || param.TotalOut != 0) { totalFlow := param.ValidFlow * int64(this.GetDBGameFree().GetBetWaterRate()) / 100 playerEx.TotalConvertibleFlow += totalFlow playerEx.TotalFlow += totalFlow playerEx.ValidCacheBetTotal += param.ValidBet //报表统计 //playerEx.SaveReportForm(int(this.GetDBGameFree().GetGameClass()), this.SceneMode, this.KeyGameId, // param.WinAmountNoAnyTax, totalFlow, param.ValidBet) //分配利润 ProfitDistribution(playerEx, param.TaxCoin, param.ClubPumpCoin, totalFlow) //上报游戏事件 playerEx.ReportGameEvent(param.TaxCoin, param.ClubPumpCoin, param.WinAmountNoAnyTax, param.ValidBet, totalFlow, param.TotalIn, param.TotalOut) } roomType := int32(this.SceneMode) if this.GameId == common.GameId_Avengers || this.GameId == common.GameId_CaiShen || this.GameId == common.GameId_EasterIsland || this.GameId == common.GameId_IceAge || this.GameId == common.GameId_TamQuoc { //复仇者联盟强制为0,所有场次操作记录放一起 roomType = 0 } baseScore := this.GetDBGameFree().GetBaseScore() if common.IsLocalGame(int(this.GameId)) { baseScore = this.BaseScore } Name := param.PlayerName if playerEx != nil { Name = param.PlayerName } log := model.NewGamePlayerListLogEx(snid, param.LogId, param.Platform, param.Channel, param.Promoter, param.PackageTag, this.GameId, baseScore, this.SceneId, int32(this.GetGameMode()), this.GetGameFreeId(), param.TotalIn, param.TotalOut, this.ClubId, this.RoomId, param.TaxCoin, param.ClubPumpCoin, roomType, param.BetAmount, param.WinAmountNoAnyTax, this.KeyGameId, Name, this.GetDBGameFree().GetGameClass(), param.IsFirstGame, this.GetMatch().GetMatchSortId(), int64(this.GetMatch().GetMatchType()), param.IsFree, param.WinSmallGame, param.WinTotal) if log != nil { LogChannelSingleton.WriteLog(log) } } } } func (this *Scene) IsPlayerFirst(p *Player) bool { if p == nil { return false } if p.GDatas != nil { if data, ok := p.GDatas[this.KeyGameId]; ok { if data.Statics.GameTimes <= 1 { return true } return false } return true } return false } func (this *Scene) RobotIsLimit() bool { if this.robotLimit != 0 { if this.IsCoinScene() { if this.robotLimit <= this.robotNum { return true } // 房间需要给真人留一个空位 //if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Priority && this.playerNum-this.realPlayerNum-1 <= this.robotNum { // 没有真人的房间需要给真人留一个空位 if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Priority && this.GetPlayerNum()-1 <= this.robotNum { return true } } else if this.IsHundredScene() { if this.robotNum >= this.robotLimit { return true } } } return false } func (this *Scene) RandRobotCnt() { if this.GetDBGameFree() != nil { if this.GetDBGameFree().GetMatchMode() == 1 { return } numrng := this.GetDBGameFree().GetRobotNumRng() if len(numrng) >= 2 { if numrng[1] == numrng[0] { this.robotLimit = int(numrng[0]) } else { if numrng[1] < numrng[0] { numrng[1], numrng[0] = numrng[0], numrng[1] } this.robotLimit = int(numrng[0] + this.Rand.Int31n(numrng[1]-numrng[0]+1)) } } //logger.Logger.Tracef("===(this *Scene) RandRobotCnt() sceneid:%v gameid:%v mode:%v robotLimit:%v robotNum:%v", this.SceneId, this.GameId, this.GameMode, this.robotLimit, this.robotNum) } } func (this *Scene) GetRobotTime() int64 { l := int64(common.RandInt(model.NormalParamData.RobotRandomTimeMin, model.NormalParamData.RobotRandomTimeMax)) return l + time.Now().Unix() } func (this *Scene) IsPreCreateScene() bool { return this.GetDBGameFree().GetCreateRoomNum() > 0 } func (this *Scene) TryInviteRobot() { if this.aiMgr != nil { return } // 游戏配置错误 if this.GetDBGameFree() == nil { return } // 私有房间不邀请机器人,比赛场部邀请机器人 if this.IsPrivateScene() || this.IsMatchScene() { return } // 队列匹配不邀请机器人 if this.GetDBGameFree().GetMatchMode() == 1 { return } // 不使用机器人 if this.GetDBGameFree().GetBot() == 0 { //机器人不进的场 return } // 分组模式下机器人是否使用(默认不使用) if !model.GameParamData.GameConfigGroupUseRobot && this.GroupId != 0 { return } // 对战场有真实玩家的情况才需要机器人匹配 if !this.IsRobFightGame() && this.realPlayerNum <= 0 && !this.IsHundredScene() && !this.IsPreCreateScene() { //预创建房间的对战场可以优先进机器人,如:21点 判断依据:CreateRoomNum return } switch this.GetDBGameFree().GetGameType() { case common.GameType_Fishing: if this.robotNum >= this.robotLimit { return } } tNow := time.Now() if tNow.Before(this.nextInviteTime) { return } if model.GameParamData.EnterAfterStartSwitch && this.IsCoinScene() && this.Gaming && !this.bEnterAfterStart { return } if this.robotNumLastInvite == this.robotNum { this.inviteInterval = this.inviteInterval + 1 if this.inviteInterval > model.GameParamData.RobotInviteIntervalMax { this.inviteInterval = model.GameParamData.RobotInviteIntervalMax } } else { this.inviteInterval = model.GameParamData.RobotInviteInitInterval } this.ResetNextInviteTime() this.robotNumLastInvite = this.robotNum if !this.RobotIsLimit() { var robCnt int if this.robotLimit != 0 { if this.IsCoinScene() { if this.robotNum >= this.robotLimit { //机器人数量已达上限 return } hadCnt := len(this.Players) robCnt = this.robotLimit - this.robotNum if robCnt > this.GetPlayerNum()-hadCnt { robCnt = this.GetPlayerNum() - hadCnt } } else if this.IsHundredScene() { robCnt = this.robotLimit - this.robotNum } } else { if this.IsCoinScene() { if this.IsFull() { return } hadCnt := len(this.Players) robCnt = this.GetPlayerNum() - hadCnt if this.realPlayerNum == 0 { //一个真人都没有,不让机器人坐满房间 robCnt-- } } } if robCnt > 0 { var num int32 if this.GetDBGameFree().GameId == common.GameId_ChesstitiansCambodianRobot { num = int32(robCnt) } else { num = this.Rand.Int31n(int32(robCnt + 1)) } if num > 0 { if this.IsCoinScene() /* && this.gaming*/ { //如果牌局正在进行中,一个一个进 num = 1 } //logger.Logger.Tracef("(this *Scene)(groupid:%v sceneid:%v) TryInviteRobot(%v) current robot(%v+%v) robotlimit(%v)", this.groupId, this.sceneId, this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, num, this.robotLimit) //同步下房间里的参数' NpcServerAgentSingleton.SyncDBGameFree(int(this.SceneId), this.GetDBGameFree()) //然后再邀请 NpcServerAgentSingleton.Invite(int(this.SceneId), int(num), this.GetDBGameFree().Id) } } } } func (this *Scene) ResetNextInviteTime() { this.nextInviteTime = time.Now().Add(time.Second * (time.Duration(this.Rand.Int63n(2+this.inviteInterval)) + 1)) } // 是否有真人参与游戏 func (this *Scene) IsRealInGame() bool { for _, player := range this.Players { if player != nil && player.IsGameing() && !player.IsRob { return true } } return false } // 是否都是真人 func (this *Scene) IsAllRealInGame() bool { for _, player := range this.Players { if player != nil && player.IsGameing() && player.IsRob { return false } } return true } // 是否开启机器人对战游戏 func (this *Scene) IsRobFightGame() bool { if this.GetDBGameFree() == nil { return false } if this.GetDBGameFree().GetAi()[0] == 1 && model.GameParamData.IsRobFightTest == true { return true } return false } // 百人场机器人离场规则 func (this *Scene) RobotLeaveHundred() { for _, p := range this.Players { if p != nil { leave := false var reason int //if p.trusteeship >= 5 { // leave = true // reason = common.PlayerLeaveReason_LongTimeNoOp //} if !leave && !p.IsOnLine() && time.Now().Sub(p.DropTime) > 30*time.Second { leave = true reason = common.PlayerLeaveReason_DropLine } if !leave && p.IsRob { if !this.CoinInLimit(p.Coin) { //钱少 leave = true reason = common.PlayerLeaveReason_Bekickout } else if this.CoinOverMaxLimit(p.Coin, p) { //钱多 leave = true reason = common.PlayerLeaveReason_Normal } else if p.Coin < int64(this.GetDBGameFree().GetBetLimit()) { //少于下注限额 leave = true reason = common.PlayerLeaveReason_Normal } } if leave { this.PlayerLeave(p, reason, leave) } } } } func (this *Scene) RandInt(args ...int) int { switch len(args) { case 0: return this.Rand.Int() case 1: if args[0] != 0 { return this.Rand.Intn(args[0]) } else { return 0 } default: l := args[0] u := args[1] switch { case l == u: { return l } case l > u: { return u + this.Rand.Intn(l-u) } default: { return l + this.Rand.Intn(u-l) } } } } func (this *Scene) CheckNeedDestroy() bool { //if common.IsLocalGame(this.GameId) { return ServerStateMgr.GetState() == common.GAME_SESS_STATE_OFF || this.graceDestroy //} else { // return (ServerStateMgr.GetState() == common.GAME_SESS_STATE_OFF || this.graceDestroy) || (this.IsPrivateScene() && this.NumOfGames >= this.TotalOfGames) //} } func (this *Scene) GetRecordId() string { if this.rr != nil { return this.rr.id } return fmt.Sprintf("%d%d%v%d", this.GameId, this.SceneId, this.GameNowTime.Format(ReplayIdTf), this.NumOfGames) } func (this *Scene) RandTakeCoin(p *Player) (takeCoin, leaveCoin, gameTimes int64) { if p.IsRob && p.IsLocal { dbGameFree := this.GetDBGameFree() takerng := dbGameFree.GetRobotTakeCoin() if len(takerng) >= 2 && takerng[1] > takerng[0] { if takerng[0] < dbGameFree.GetLimitCoin() { takerng[0] = dbGameFree.GetLimitCoin() } takeCoin = int64(common.RandInt(int(takerng[0]), int(takerng[1]))) } else { maxlimit := int64(dbGameFree.GetMaxCoinLimit()) if maxlimit != 0 && p.Coin > maxlimit { logger.Logger.Trace("Player coin:", p.Coin) //在下限和上限之间随机,并对其的100的整数倍 takeCoin = int64(common.RandInt(int(dbGameFree.GetLimitCoin()), int(maxlimit))) logger.Logger.Trace("Take coin:", takeCoin) } if maxlimit == 0 && this.IsCoinScene() { maxlimit = int64(common.RandInt(10, 50)) * int64(dbGameFree.GetLimitCoin()) takeCoin = int64(common.RandInt(int(dbGameFree.GetLimitCoin()), int(maxlimit))) logger.Logger.Trace("Take coin:", takeCoin) } } takeCoin = takeCoin / 100 * 100 //离场金币 leaverng := dbGameFree.GetRobotLimitCoin() if len(leaverng) >= 2 { leaveCoin = int64(leaverng[0] + rand.Int63n(leaverng[1]-leaverng[0])) } } return } // TryBillExGameDrop 掉落道具 func (this *Scene) TryBillExGameDrop(p *Player) { if p.IsRob { return } this.DropCollectBox(p) baseScore := this.GetDBGameFree().BaseScore if common.IsLocalGame(int(this.GameId)) { baseScore = this.BaseScore } if baseScore == 0 { return } // 场次掉落开关 if this.GetDBGameFree().IsDrop != 1 { return } // 渠道开关 if !ConfigMgrInst.IsOn(p.Platform, common.ChannelSwitchDropItem, p.LastChannel) { return } dropInfo := srvdata.GameDropMgrSingleton.GetDropInfoByBaseScore(baseScore) if dropInfo != nil && len(dropInfo) != 0 { realDrop := make(map[int32]int32) for _, drop := range dropInfo { //概率 randTmp := rand.Int31n(10000) if randTmp < drop.Rate { //个数 num := drop.MinAmount if drop.MaxAmount > drop.MinAmount { num = rand.Int31n(drop.MaxAmount-drop.MinAmount+1) + drop.MinAmount } oldNum := num a := math.Max(float64(p.MoneyTotal), 50) * 10.0 / math.Max(float64(p.VCardCost), 500.0) num = int32(float64(num) * math.Min(a, 1.5)) if num == 0 { // 50%概率给oldNum if rand.Int31n(100) < 50 { num = oldNum } } realDrop[drop.ItemId] = num } } if realDrop != nil && len(realDrop) != 0 { //通知客户端游戏内额外掉落 pack := &player.SCGameExDropItems{} pack.Items = make(map[int32]int32) for id, num := range realDrop { pack.Items[id] = proto.Int32(num) itemData := srvdata.GameItemMgr.Get(p.Platform, id) if itemData != nil { p.AddItems(&model.AddItemParam{ P: &p.PlayerData, Change: nil, GainWay: common.GainWay_Game, Operator: "system", Remark: fmt.Sprintf("游戏掉落%v", id), GameId: int64(this.GameId), GameFreeId: int64(this.GetGameFreeId()), }) } } if len(pack.Items) > 0 { p.SendToClient(int(player.PlayerPacketID_PACKET_SCGAMEEXDROPITEMS), pack) logger.Logger.Trace("SCGAMEEXDROPITEMS ", pack) } } } } // DropCollectBox 掉落集卡礼盒 func (this *Scene) DropCollectBox(p *Player) { if p == nil || p.IsRob || ConfigMgrInst.GetConfig(p.Platform).WelfareCollectConfig.Switch != model.WelfareOpen { return } data := srvdata.PBDB_CollectBoxGainMgr.GetData(this.GetGameFreeId()) if data == nil { return } n := this.RandInt(100) if n < int(data.GetRate()) { pack := &player.SCGameExDropItems{} pack.Items = make(map[int32]int32) itemData := srvdata.GameItemMgr.Get(p.Platform, common.ItemIDCollectBox) if itemData != nil { pack.Items = map[int32]int32{itemData.Id: 1} p.AddItems(&model.AddItemParam{ P: &p.PlayerData, Change: []*model.Item{ { ItemId: itemData.Id, ItemNum: 1, }, }, GainWay: common.GainWay_Game, Operator: "system", Remark: fmt.Sprintf("游戏掉落%v", itemData.Id), GameId: int64(this.GameId), GameFreeId: int64(this.GetGameFreeId()), }) } if len(pack.Items) > 0 { p.SendToClient(int(player.PlayerPacketID_PACKET_SCGAMEEXDROPITEMS), pack) logger.Logger.Trace("SCGAMEEXDROPITEMS", pack) } } } // 生成名字 func (this *Scene) RandNickName() string { //if rand.Int31n(100) < 60 { pool := srvdata.PBDB_NameMgr.Datas.GetArr() cnt := int32(len(pool)) if cnt > 0 { return pool[rand.Int31n(cnt)].GetName() } //} return "Guest" } func (this *Scene) GetRobotNum() int { return this.robotNum } func (this *Scene) GetRealPlayerNum() int { return this.realPlayerNum } func (this *Scene) GetBaseScore() int32 { if this.BaseScore > 0 { return this.BaseScore } return this.GetDBGameFree().GetBaseScore() } func (this *Scene) PlayerPoolOdds(p *Player) int32 { config := ConfigMgrInst.GetConfig(p.Platform).PlayerPool if config == nil { return 0 } if !config.GetPlayerPoolSwitch() || p == nil { return 0 } pCoin := p.TotalOut - p.PlayerTax - p.TotalIn var gameCoin int64 var upLine, lowLine int64 lowLine = p.GetPoolLower(config) upLine = p.GetPoolUpper(config) odds := int32(p.GetPoolOdds(config)) p.TestLog = append(p.TestLog, fmt.Sprintf("个人水池调控 gameID:%v 兑换金币:%v 玩家初始值:%v, 游戏类型:%v, gameCoin:%v, 上线:%v, 下线:%v 概率:%v", this.GameId, p.DiamondToCoin, pCoin, this.GetDBGameFree().GetGameType(), gameCoin, upLine, lowLine, odds)) return odds } // GetPlayerOdds 获取玩家发牌调控概率 func (this *Scene) GetPlayerOdds(p *Player, gameId int, hasRobot bool) int32 { if !this.IsControl(hasRobot) { return 0 } if p == nil { return 0 } // 黑白名单概率 odds, ok := p.BlackWhiteOdds(gameId) if ok { return odds } // 新手补偿概率 odds, ok = p.NoviceOdds(gameId) if ok { return odds } var f, g, t, ret int32 // 个人水池概率 g = this.PlayerPoolOdds(p) setting := CoinPoolMgr.GetCoinPoolSetting(this.Platform, this.GetGameFreeId(), this.GroupId) if setting != nil && setting.GetSwitch() == 0 { // 场次水池概率 f = CoinPoolMgr.GetCoinPoolOdds(this.Platform, this.GetGameFreeId(), this.GroupId) cfg := ConfigMgrInst.GetConfig(p.Platform).PlayerPool if cfg != nil && cfg.PlayerPoolSwitch { if g > 0 { t = f + (1000-f)*g/1000 ret = t } else if g < 0 { t = f + (1000+f)*g/1000 ret = t } else { ret = f } } else { ret = f } //logger.Logger.Tracef("TienLenSceneData snid(%v) 水池配置 水位:%v 配置:%+v", // p.SnId, CoinPoolMgr.GetCoin(this.GetGameFreeId(), this.Platform, this.GroupId), *setting) p.TestLog = append(p.TestLog, fmt.Sprintf("水位:%v 水池配置:%+v", CoinPoolMgr.GetCoin(this.GetGameFreeId(), this.Platform, this.GroupId), *setting)) } else { ret = g } //logger.Logger.Tracef("TienLenSceneData snid(%v) 个人及场次水池调控 hasRobot:%v 个人水池:%v 场次水池:%v 概率:%v", p.SnId, hasRobot, g, f, ret) p.TestLog = append(p.TestLog, fmt.Sprintf("个人及场次水池调控 有机器人:%v 个人水池:%v 场次水池:%v 概率:%v", hasRobot, g, f, ret)) return ret } type PlayerDataParam struct { HasRobotGaming bool Data *server.GWPlayerData } // SyncPlayerDatas 同步玩家游戏数据到worldsrv // hasRobotGaming 本局是否有机器人参与游戏 // 返回 溢出金额 func (this *Scene) SyncPlayerDatas(param *PlayerDataParam) int64 { if param == nil || param.Data == nil { return 0 } var n int64 // 比赛场,私人房,公共房无机器人不统计黑白名单输赢金额 if this.IsControl(param.HasRobotGaming) { for _, v := range param.Data.Datas { if v.WBGain == 0 { v.WBGain = v.Gain } if v.WBGain != 0 { if p := this.GetPlayer(v.SnId); p != nil { n = p.WBUpdate(v.WBGain) } } } } this.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERDATA), param.Data) logger.Logger.Trace("Send PlayerData ===>", param.Data) return n } type StaticParam struct { SnId int32 // 玩家id Gain int64 // 输赢金币(税后) GainTax int64 // 赢取金币时的税收 IsAddTimes bool // 是否统计游戏次数 HasRobotGaming bool // 是否有机器人玩本局游戏 WinState int32 // 输赢状态 1 赢 2 输 3 和 } // IsControl 是否调控 func (this *Scene) IsControl(hasRobotGaming bool) bool { return !this.IsMatchScene() && !this.IsPrivateScene() && !(this.IsFreePublic() && !hasRobotGaming) } // Statistics 玩家游戏数据统计 // 包含水池统计,黑白名单统计,新手调控统计,个人水池统计 func (this *Scene) Statistics(param *StaticParam) { if param == nil { return } p := this.GetPlayer(param.SnId) if p == nil || p.IsRob { return } _, isNovice := p.NoviceOdds(int(this.GameId)) isControl := this.IsControl(param.HasRobotGaming) // 需要调控的房间 var wbLevel = p.WBLevel // 原来的黑白名单等级; 注意SyncPlayerDatas会修改WBLevel var addGain int64 // 玩家溢出金额 // 黑白名单 // 解除黑白名单,记录黑白名单投入产出 addGain += this.SyncPlayerDatas(&PlayerDataParam{ HasRobotGaming: param.HasRobotGaming, Data: &server.GWPlayerData{ Datas: []*server.PlayerData{ { SnId: param.SnId, Gain: param.Gain, Tax: param.GainTax, Coin: p.Coin, GameCoinTs: p.GameCoinTs, WinState: param.WinState, }, }, GameFreeId: this.GetGameFreeId(), SceneId: int32(this.SceneId), }, }) logger.Logger.Tracef("Statistics gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain) // 比赛场,私人房不统计 if this.IsMatchScene() || this.IsPrivateScene() { return } var totalIn int64 var totalOut int64 now := time.Now() if param.Gain > 0 { totalOut = param.Gain + param.GainTax } else { totalIn = -param.Gain } var statics []*model.PlayerGameStatics keyGameId := strconv.Itoa(this.GetGameId()) keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId())) // 当天数据统计 // 按场次分 if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok { statics = append(statics, data) } else { gs := model.NewPlayerGameStatics() p.TodayGameData.CtrlData[keyGameFreeId] = gs statics = append(statics, gs) } // 按游戏分 if data, ok := p.TodayGameData.CtrlData[keyGameId]; ok { statics = append(statics, data) } else { data = model.NewPlayerGameStatics() p.TodayGameData.CtrlData[keyGameId] = data statics = append(statics, data) } // 按场次分 if data, ok := p.GDatas[keyGameFreeId]; ok { if data.FirstTime.IsZero() { data.FirstTime = now } statics = append(statics, &data.Statics) } else { data = &model.PlayerGameInfo{FirstTime: now} p.GDatas[keyGameFreeId] = data statics = append(statics, &data.Statics) } // 按游戏分 if data, ok := p.GDatas[keyGameId]; ok { if data.FirstTime.IsZero() { data.FirstTime = now } statics = append(statics, &data.Statics) } else { data = &model.PlayerGameInfo{FirstTime: now} p.GDatas[keyGameId] = data statics = append(statics, &data.Statics) } // 新手输赢统计 if !model.GameParamData.CloseNovice && !common.InSliceInt(model.GameParamData.CloseNoviceGame, int(this.GameId)) && isControl && wbLevel == 0 && isNovice { keyNoviceGameId := common.GetKeyNoviceGameId(int(this.GameId)) var gs *model.PlayerGameStatics if data, ok := p.GDatas[keyNoviceGameId]; ok { statics = append(statics, &data.Statics) gs = &data.Statics } else { data = &model.PlayerGameInfo{FirstTime: time.Now(), Statics: *model.NewPlayerGameStatics()} p.GDatas[keyNoviceGameId] = data statics = append(statics, &data.Statics) gs = &data.Statics } // 溢出 data := srvdata.PBDB_NewPlayerMgr.GetData(int32(this.GameId)) if data != nil { switch data.GetCondition1() { case 2: // gameId输赢金额 if gs != nil { out := gs.TotalOut + totalOut in := gs.TotalIn + totalIn tax := gs.Tax + param.GainTax cur := out - tax - in if cur > data.GetConditionValue1() { addGain += cur - data.GetConditionValue1() } } } switch data.GetCondition2() { case 2: // gameId输赢金额 if gs != nil { out := gs.TotalOut + totalOut in := gs.TotalIn + totalIn tax := gs.Tax + param.GainTax cur := out - tax - in if cur > data.GetConditionValue2() { addGain += cur - data.GetConditionValue2() } } } } } logger.Logger.Tracef("Statistics Novice gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain) // 个人输赢统计条件(个人水池) // 黑白名单和新手调控,溢出金币统计到个人水池 cfg := ConfigMgrInst.GetConfig(p.Platform).PlayerPool isPlayerPool := cfg != nil && cfg.PlayerPoolSwitch && isControl && ((wbLevel == 0 && !isNovice) || addGain > 0) if isPlayerPool { keyGameType := common.GetKeyGameType(int(this.GetDBGameFree().GetGameType())) gs, ok := p.GDatas[keyGameType] if !ok { gs = &model.PlayerGameInfo{FirstTime: time.Now()} p.GDatas[keyGameType] = gs } if addGain == 0 { // 正常统计 // 游戏类型输赢统计(个人水池调控使用) statics = append(statics, &gs.Statics) } else { // 溢出统计;只有多赢的值,多输的不计算 if wbLevel >= 0 { gs.Statics.TotalOut += addGain } } logger.Logger.Tracef("Statistics PlayerPool gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain) } for _, data := range statics { if data != nil { data.TotalIn += totalIn data.TotalOut += totalOut data.Tax += param.GainTax if param.IsAddTimes { data.GameTimes++ if param.Gain > 0 { data.WinGameTimes++ data.WinGameTimesNum++ data.LoseGameTimesNum = 0 } else if param.Gain < 0 { data.LoseGameTimes++ data.LoseGameTimesNum++ data.WinGameTimesNum = 0 } else { data.DrawGameTimes++ data.WinGameTimesNum = 0 data.LoseGameTimesNum = 0 } } } } // 玩家身上元数据 if param.IsAddTimes { p.GameTimes++ } if param.Gain > 0 { if param.IsAddTimes { p.WinTimes++ } p.WinCoin += totalOut p.TaxCoin += param.GainTax if isPlayerPool && srvdata.GameFreeMgr.IsPlayerPool(int(this.GameId)) { p.TotalOut += totalOut p.PlayerTax += param.GainTax } } else if param.Gain < 0 { if param.IsAddTimes { p.FailTimes++ } p.FailCoin += totalIn if isPlayerPool && srvdata.GameFreeMgr.IsPlayerPool(int(this.GameId)) { p.TotalIn += totalIn } } else { if param.IsAddTimes { p.DrawTimes++ } } // 水池统计 if isControl && ((wbLevel == 0 && !isNovice) || addGain > 0) { if addGain == 0 { CoinPoolMgr.PushCoin(this.GetGameFreeId(), this.GroupId, this.Platform, -param.Gain) } else { // 溢出统计;只有多赢的值,多输的不计算 if wbLevel >= 0 { CoinPoolMgr.PushCoin(this.GetGameFreeId(), this.GroupId, this.Platform, -addGain) } } logger.Logger.Tracef("Statisticsis CoinPool gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain) } } type StaticLabaParam struct { SnId int32 // 玩家id Gain int64 // 输赢金币(税后) GainTax int64 // 赢取金币时的税收 IsAddTimes bool // 是否统计游戏次数 } // StaticsLaba 拉霸游戏数据统计,一次下注记录一次 // 不含水池统计,黑白名单统计,在游戏中另外处理 func (this *Scene) StaticsLaba(param *StaticLabaParam) { if param == nil { return } p := this.GetPlayer(param.SnId) if p == nil || p.IsRob { return } // 比赛场,私人房不统计 if this.IsMatchScene() || this.IsPrivateScene() { return } var totalIn int64 var totalOut int64 now := time.Now() if param.Gain > 0 { totalOut = param.Gain + param.GainTax } else { totalIn = -param.Gain } var statics []*model.PlayerGameStatics keyGameId := strconv.Itoa(this.GetGameId()) keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId())) // 当天数据统计 // 按场次分 if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok { statics = append(statics, data) } else { gs := model.NewPlayerGameStatics() p.TodayGameData.CtrlData[keyGameFreeId] = gs statics = append(statics, gs) } // 按游戏分 if data, ok := p.TodayGameData.CtrlData[keyGameId]; ok { statics = append(statics, data) } else { data = model.NewPlayerGameStatics() p.TodayGameData.CtrlData[keyGameId] = data statics = append(statics, data) } // 按场次分 if data, ok := p.GDatas[keyGameFreeId]; ok { if data.FirstTime.IsZero() { data.FirstTime = now } statics = append(statics, &data.Statics) } else { data = &model.PlayerGameInfo{FirstTime: now} p.GDatas[keyGameFreeId] = data statics = append(statics, &data.Statics) } // 按游戏分 if data, ok := p.GDatas[keyGameId]; ok { if data.FirstTime.IsZero() { data.FirstTime = now } statics = append(statics, &data.Statics) } else { data = &model.PlayerGameInfo{FirstTime: now} p.GDatas[keyGameId] = data statics = append(statics, &data.Statics) } for _, data := range statics { if data != nil { data.TotalIn += totalIn data.TotalOut += totalOut data.Tax += param.GainTax if param.IsAddTimes { data.GameTimes++ if param.Gain > 0 { data.WinGameTimes++ data.WinGameTimesNum++ data.LoseGameTimesNum = 0 } else if param.Gain < 0 { data.LoseGameTimes++ data.LoseGameTimesNum++ data.WinGameTimesNum = 0 } else { data.DrawGameTimes++ data.WinGameTimesNum = 0 data.LoseGameTimesNum = 0 } } } } // 玩家身上元数据 if param.IsAddTimes { p.GameTimes++ } if param.Gain > 0 { if param.IsAddTimes { p.WinTimes++ } p.WinCoin += totalOut p.TaxCoin += param.GainTax } else if param.Gain < 0 { if param.IsAddTimes { p.FailTimes++ } p.FailCoin += totalIn } else { if param.IsAddTimes { p.DrawTimes++ } } } func (this *Scene) TryRelease() { if !this.IsMatchScene() && this.realPlayerNum == 0 { this.Destroy(true) } }