package base import ( "fmt" rawproto "google.golang.org/protobuf/proto" "math" "mongo.games.com/game/common" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/player" "mongo.games.com/game/protocol/server" "mongo.games.com/game/srvdata" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/timer" //rawproto "github.com/golang/protobuf/proto" "math/rand" "time" ) // 对应到客户端的一个玩家对象. const ( PlayerState_Online int = 1 << iota //在线标记 1 PlayerState_Ready //准备标记 2 PlayerState_SceneOwner //房主标记 3 PlayerState_Choke //呛标记 被复用于金花,是否被动弃牌 4 PlayerState_Ting //听牌标记 5 金花复用,标记最后押注时,是否看牌 PlayerState_NoisyBanker //闹庄标记 6 金花复用,标记allin时,是否看牌 PlayerState_WaitOp //等待操作标记 7 PlayerState_Auto //托管状态 8 PlayerState_Check //已看牌状态 9 PlayerState_Fold //弃牌状态 10 PlayerState_Lose //输状态 11 PlayerState_Win //赢状态 12 PlayerState_WaitNext //等待下一局游戏 13 PlayerState_GameBreak //不能继续游戏 14 PlayerState_Leave //暂离状态 15 PlayerState_Audience //观众标记 16 PlayerState_AllIn //allin标记 17 PlayerState_FinalAllIn //最后一圈,最后一个人allin标记 18 PlayerState_Show //亮牌标记 19 PlayerState_EnterSceneFailed //进场失败 20 PlayerState_PKLost //发起Pk,失败 21 PlayerState_IsChangeCard //牛牛标识是否换牌 22 PlayerState_IsPayChangeCard //牛牛标识是否充值换牌 23 PlayerState_Bankruptcy //玩家破产 24 PlayerState_MatchQuit //退赛标记 25 PlayerState_AllFollow //跟到底状态 26 PlayerState_SAdjust //单控状态 27 PlayerState_Max ) // 玩家事件 const ( PlayerEventEnter int = iota //进入事件 PlayerEventLeave //离开事件 PlayerEventDropLine //掉线 PlayerEventRehold //重连 PlayerEventReturn //返回房间 gs 添加 PlayerEventRecharge //冲值事件 PlayerEventAddCoin //其他加减币事件(例如:小游戏) AudienceEventEnter //观众进入事件 AudienceEventLeave //观众离开事件 AudienceEventDropLine //观众掉线 AudienceEventRehold //观众重连 ) type Player struct { model.PlayerData //po 持久化对象 ExtraData interface{} //扩展接口 gateSess *netlib.Session //所在GateServer的session worldSess *netlib.Session //所在WorldServer的session scene *Scene //当前所在个Scene ai AI //ai接口 sid int64 //对应客户端的sessionId gateSid int64 //对应网关的sessionId Longitude int32 //经纬度 Latitude int32 //经纬度 city string //城市 flag int //状态标记 Pos int //当前位置 dirty bool //脏标记 Billed bool //是否已经结算过了 AgentCode string //代理商编号 Coin int64 //金币 serviceFee int64 //服务费|税收 TotalBet int64 //总下注额(从进房间开始,包含多局游戏的下注) disbandGen int //第几次解散申请 hAuto timer.TimerHandle //托管handle GameTimes int32 //游戏次数 winTimes int //胜利次数 lostTimes int //失败次数 ActiveLeave bool //主动暂离 OpCode player.OpResultCode //错误码 takeCoin int64 //携带金币 ExpectLeaveCoin int64 //期望离场时的金币[机器人用] ExpectGameTime int32 //期望进行的局数[机器人用] CurIsWin int64 //当局输赢 负数:输 0:平局 正数:赢 currentCoin int64 //本局结束后剩余 CurrentBet int64 //本局下注额 CurrentTax int64 //本局税收 StartCoin int64 //本局开始金币 LastSyncCoin int64 // IsQM bool //是否是全民推广用户 LastOPTimer time.Time //玩家最后一次操作时间 Trusteeship int32 //玩家托管了几局 ValidCacheBetTotal int64 //有效下注缓存 isFightRobot bool //测试机器人,这种机器人可以用作记录水池数据,方便模拟用户输赢 DropTime time.Time //掉线时间 cparams map[string]string //平台登陆数据 Iparams map[int]int64 //整形参数 sparams map[int]string //字符参数 IsLocal bool //是否本地player Items map[int32]int64 //背包数据, 不可直接修改,使用 AddItems 方法 MatchParams []int32 //比赛参数 排名、段位、假snid、假角色、假皮肤 MatchRobotGrades []MatchRobotGrade TestLog []string // 调试日志 RankScore map[int32]int64 // 段位积分 } type MatchRobotGrade struct { CopySnid int32 Grade int32 } func NewPlayer(sid int64, data []byte, ws, gs *netlib.Session) *Player { p := &Player{ sid: sid, worldSess: ws, gateSess: gs, flag: PlayerState_Online, Pos: -1, Longitude: -1, Latitude: -1, cparams: make(map[string]string), //平台登陆数据 Iparams: make(map[int]int64), //整形参数 sparams: make(map[int]string), //字符参数 Items: make(map[int32]int64), RankScore: make(map[int32]int64), } // 需要make的,统一在这里初始化默认值,别的地方就不用再初始化了 p.PlayerData = model.PlayerData{ //TotalGameData: make(map[int][]*model.PlayerGameTotal), GDatas: make(map[string]*model.PlayerGameInfo), ShopTotal: make(map[int32]*model.ShopTotal), ShopLastLookTime: make(map[int32]int64), IsFoolPlayer: make(map[string]bool), } if p.init(data) { return p } return nil } func (this *Player) init(data []byte) bool { if !this.UnmarshalData(data) { return false } if this.GMLevel > 2 { this.Longitude = rand.Int31n(114103930-113216260) + 113216260 this.Latitude = rand.Int31n(34963671-34592702) + 34592702 } this.city = this.City this.LastOPTimer = time.Now() if this.GDatas == nil { this.GDatas = make(map[string]*model.PlayerGameInfo) } return true } func (this *Player) MarkFlag(flag int) { this.flag |= flag switch flag { case PlayerState_Online, PlayerState_Ready, PlayerState_Leave: this.SyncFlagToWorld() } } func (this *Player) UnmarkFlag(flag int) { this.flag &= ^flag switch flag { case PlayerState_Online, PlayerState_Ready, PlayerState_Leave: this.SyncFlagToWorld() } } func (this *Player) IsMarkFlag(flag int) bool { if (this.flag & flag) != 0 { return true } return false } func (this *Player) IsOnLine() bool { return this.IsMarkFlag(PlayerState_Online) } func (this *Player) IsReady() bool { return this.IsMarkFlag(PlayerState_Ready) } func (this *Player) IsSceneOwner() bool { return this.IsMarkFlag(PlayerState_SceneOwner) } func (this *Player) IsAuto() bool { return this.IsMarkFlag(PlayerState_Auto) } func (this *Player) IsGameing() bool { return !this.IsMarkFlag(PlayerState_WaitNext) && !this.IsMarkFlag(PlayerState_GameBreak) && !this.IsMarkFlag(PlayerState_Bankruptcy) && !this.IsMarkFlag(PlayerState_Audience) } func (this *Player) IsAllFollow() bool { return this.IsMarkFlag(PlayerState_AllFollow) } func (this *Player) SyncFlag(onlyMyself ...bool) { if this.IsLocal { return } pack := &player.SCPlayerFlag{ PlayerId: proto.Int32(this.SnId), Flag: proto.Int(this.flag), } proto.SetDefaults(pack) if len(onlyMyself) != 0 && onlyMyself[0] { this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PLAYERFLAG), pack) } else { this.Broadcast(int(player.PlayerPacketID_PACKET_SC_PLAYERFLAG), pack, 0) } //logger.Logger.Trace("SyncFlag:", pack) } func (this *Player) SyncFlagToWorld() { if this.IsLocal { return } if this.scene == nil || this.scene.IsCoinScene() || this.scene.IsMatchScene() || this.scene.IsHundredScene() { return } pack := &server.GWPlayerFlag{ SnId: proto.Int32(this.SnId), RoomId: this.scene.SceneId, Flag: proto.Int(this.flag), } proto.SetDefaults(pack) this.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERSTATE), pack) logger.Logger.Trace("SyncFlag to world:", pack) } func (this *Player) SendToClient(packetid int, rawpack interface{}, forceIgnore ...bool) bool { if this.IsLocal { return true } if !this.scene.Testing && this.scene.Gaming && this.scene.rr != nil && this.Pos != -1 && len(forceIgnore) == 0 && !this.scene.IsHundredScene() { this.scene.rr.Record(this.Pos, -1, packetid, rawpack) } if this.gateSess == nil { logger.Logger.Warnf("(this *Player) SendToClient [snid:%v packetid:%v] gatesess == nil ", this.SnId, packetid) return false } if rawpack == nil { logger.Logger.Tracef("(this *Player) SendToClient [snid:%v packetid:%v] rawpack == nil ", this.SnId, packetid) return false } if !this.IsOnLine() { logger.Logger.Warnf("(this *Player) SendToClient [snid:%v packetid:%v] Player if offline.", this.SnId, packetid) return false } if this.IsMarkFlag(PlayerState_Leave) { logger.Logger.Warnf("(this *Player) SendToClient [snid:%v packetid:%v] Player if leave.", this.SnId, packetid) return false } //logger.Logger.Trace("Send to player's packet:", packetid) return common.SendToGate(this.sid, packetid, rawpack, this.gateSess) } func (this *Player) Broadcast(packetid int, rawpack interface{}, excludeSid int64) bool { if this.scene != nil { this.scene.Broadcast(packetid, rawpack.(rawproto.Message), excludeSid) return true } return false } func (this *Player) SendToWorld(packetid int, rawpack interface{}) bool { if this.IsLocal { return true } if this.worldSess == nil { logger.Logger.Tracef("(this *Player) SendToWorld [%v] worldsess == nil ", this.Name) return false } if rawpack == nil { logger.Logger.Trace("(this *Player) SendToWorld rawpack == nil ") return false } this.scene.SendToWorld(packetid, rawpack) return true } func (this *Player) OnEnter(s *Scene) { this.scene = s this.TestLog = this.TestLog[:0] //标记房主 if this.SnId == s.Creator { this.MarkFlag(PlayerState_SceneOwner) } } func (this *Player) OnAudienceEnter(s *Scene) { this.scene = s } func (this *Player) OnRehold(newSid int64, newSess *netlib.Session) { this.sid = newSid this.gateSess = newSess this.MarkFlag(PlayerState_Online) // 2018-4-25 // 这里先注释掉,暂离的状态在LeaveRoom和ReturnRoom的消息中设置 // 如果这里清除暂离,那么在棋牌馆中,离开房间,用的状态更新为暂离状态,断线重连以后的话,在棋牌馆大厅界面看到的用户为非暂离状态, // 所以这里就先注释掉,让暂离的状态在离开和返回房间的消息中成对出现 this.UnmarkFlag(PlayerState_Leave) this.SyncFlag() } func (this *Player) OnDropLine() { this.UnmarkFlag(PlayerState_Online) if !this.scene.Gaming && this.IsReady() && !this.scene.IsMatchScene() { this.UnmarkFlag(PlayerState_Ready) } this.SyncFlag() //存在假掉线的可能吗? //this.gateSess = nil //this.sid = 0 } func (this *Player) OnAudienceDropLine() { this.gateSess = nil } func (this *Player) OnLeave(reason int) { unbindGateSess := true PlayerMgrSington.DelPlayerBySnId(this.SnId) //解绑gamesession if unbindGateSess && this.gateSess != nil { pack := &server.GGPlayerSessionUnBind{ Sid: proto.Int64(this.sid), } proto.SetDefaults(pack) this.gateSess.Send(int(server.SSPacketID_PACKET_GG_PLAYERSESSIONUNBIND), pack) } } func (this *Player) OnAudienceLeave(reason int) { PlayerMgrSington.DelPlayerBySnId(this.SnId) //解绑gamesession if this.gateSess != nil { pack := &server.GGPlayerSessionUnBind{ Sid: proto.Int64(this.sid), } proto.SetDefaults(pack) this.gateSess.Send(int(server.SSPacketID_PACKET_GG_PLAYERSESSIONUNBIND), pack) } } func (this *Player) MarshalData(gameid int) (d []byte, e error) { d, e = netlib.Gob.Marshal(&this.PlayerData) logger.Logger.Trace("(this *Player) MarshalData(gameid int)") return } func (this *Player) UnmarshalData(data []byte) bool { if len(data) == 0 { return true } err := netlib.Gob.Unmarshal(data, &this.PlayerData) if err == nil { this.dirty = true return true } else { logger.Logger.Warn("Player.SyncData err:", err) } return false } func (this *Player) OnSecTimer() { } func (this *Player) OnMiniTimer() { } func (this *Player) OnHourTimer() { } func (this *Player) OnDayTimer() { //在线跨天 数据给昨天,今天置为空 this.YesterdayGameData = this.TodayGameData this.TodayGameData = model.NewPlayerGameCtrlData() /* for k, v := range this.YesterdayGameData.CtrlData { t := &model.PlayerGameStatics{} t.AvgBetCoin = v.AvgBetCoin this.TodayGameData.CtrlData[k] = t } */ } func (this *Player) OnMonthTimer() { } func (this *Player) OnWeekTimer() { } func (this *Player) GetName() string { return this.Name } func (this *Player) MarkDirty() { this.dirty = true } const ( SyncFlag_ToClient = 1 << iota //同步给客户端 SyncFlag_ToWorld //同步给服务端 SyncFlag_Broadcast //广播给房间内的用户 ) func (this *Player) AddCoin(num int64, gainWay int32, syncFlag int, oper, remark string) { if num == 0 { return } this.Coin += num if this.scene != nil { if !this.IsRob && !this.scene.Testing { //机器人log排除掉 log := model.NewCoinLogEx(&model.CoinLogParam{ Platform: this.Platform, SnID: this.SnId, Channel: this.Channel, ChangeType: common.BillTypeCoin, ChangeNum: num, RemainNum: this.Coin, Add: 0, LogType: gainWay, GameID: int64(int32(this.scene.GetGameId())), GameFreeID: int64(this.scene.GetGameFreeId()), BaseCoin: int64(this.scene.GetBaseScore()), Operator: oper, Remark: remark, }) if log != nil { this.GameCoinTs = log.Time.UnixNano() this.dirty = true LogChannelSingleton.WriteLog(log) } } //确保金币场金币数量不小于0 if this.Coin < 0 { this.Coin = 0 } } //增加玩家经验 if num > 0 { exp := num / 100 this.AddPlayerExp(exp) logger.Logger.Trace("玩家获取金币 增加玩家经验值:", exp) } if (syncFlag & SyncFlag_ToClient) != 0 { pack := &player.SCPlayerCoinChange{ SnId: proto.Int32(this.SnId), AddCoin: proto.Int64(num), RestCoin: proto.Int64(this.Coin), } proto.SetDefaults(pack) if (syncFlag & SyncFlag_Broadcast) != 0 { this.Broadcast(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack, 0) } else { this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack) } logger.Logger.Trace("(this *Player) AddCoin SCPlayerCoinChange:", pack) } } func (this *Player) AddCoinNoLog(num int64, syncFlag int) { if num == 0 { return } this.Coin += num if this.scene != nil { if !this.IsRob && !this.scene.Testing { //机器人log排除掉 this.dirty = true } } if (syncFlag & SyncFlag_ToClient) != 0 { pack := &player.SCPlayerCoinChange{ SnId: proto.Int32(this.SnId), AddCoin: proto.Int64(num), RestCoin: proto.Int64(this.Coin), } proto.SetDefaults(pack) if (syncFlag & SyncFlag_Broadcast) != 0 { this.Broadcast(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack, 0) } else { this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack) } logger.Logger.Trace("(this *Player) AddCoinNoLog SCPlayerCoinChange:", pack) } } func (this *Player) AddCoinAsync(num int64, gainWay int32, notifyC, broadcast bool, oper, remark string, writeLog bool) { if num == 0 { return } this.Coin += num if this.scene != nil { if !this.IsRob && !this.scene.Testing && writeLog { //机器人log排除掉 log := model.NewCoinLogEx(&model.CoinLogParam{ Platform: this.Platform, SnID: this.SnId, Channel: this.Channel, ChangeType: common.BillTypeCoin, ChangeNum: num, RemainNum: this.Coin, Add: 0, LogType: gainWay, GameID: int64(this.scene.GetGameId()), GameFreeID: int64(this.scene.GetGameFreeId()), BaseCoin: int64(this.scene.GetBaseScore()), Operator: oper, Remark: remark, }) if log != nil { this.GameCoinTs = log.Time.UnixNano() this.dirty = true LogChannelSingleton.WriteLog(log) } } //确保金币场金币数量不小于0 if this.Coin < 0 { this.Coin = 0 } } if notifyC { pack := &player.SCPlayerCoinChange{ SnId: proto.Int32(this.SnId), AddCoin: proto.Int64(num), RestCoin: proto.Int64(this.Coin), } proto.SetDefaults(pack) if broadcast { this.Broadcast(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack, 0) } else { this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PLAYERCOINCHANGE), pack) } } } func (this *Player) AddChessGrade(num int64) { if num == 0 { return } this.ChessGrade += num if this.ChessGrade < 0 { this.ChessGrade = 0 } } func (this *Player) AddRankScore(rankType int32, num int64) { if num == 0 { return } oldScore := this.RankScore[rankType] var lessScore int64 switch rankType { case 1: lessScore = 10001 default: lessScore = 10001 } if oldScore < lessScore && num < 0 { return } this.RankScore[rankType] += num if this.RankScore[rankType] < 0 { this.RankScore[rankType] = 0 } if oldScore >= lessScore && this.RankScore[rankType] < lessScore { this.RankScore[rankType] = lessScore } } func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, in, out int64) { // 记录玩家 首次参与该场次的游戏时间 游戏次数 var gameFirstTime, gameFreeFirstTime time.Time var gameTimes, gameFreeTimes int64 data, ok := this.GDatas[this.scene.KeyGamefreeId] if ok { gameFirstTime = data.FirstTime gameTimes = data.Statics.GameTimes } // 记录玩家 首次参与该游戏时间 游戏次数(不区分场次) dataGame, ok := this.GDatas[this.scene.KeyGameId] if ok { gameFreeFirstTime = dataGame.FirstTime gameFreeTimes = dataGame.Statics.GameTimes } gamingTime := int32(time.Now().Sub(this.scene.GameNowTime).Seconds()) LogChannelSingleton.WriteMQData(model.GenerateGameEvent(model.CreatePlayerGameRecEvent(this.SnId, tax, taxex, changeCoin, validbet, validFlow, in, out, int32(this.scene.GameId), this.scene.GetGameFreeId(), int32(this.scene.GameMode), this.scene.GetRecordId(), this.Channel, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, this.CreateTime, gamingTime, gameFirstTime, gameFreeFirstTime, gameTimes, gameFreeTimes, this.LastLoginTime, this.TelephonePromoter, this.DeviceId))) } // 汇总玩家该次游戏总产生的税收 // 数据用途: 平台和推广间分账用,确保数据计算无误, // 注意:该税收不包含俱乐部的抽水 // tax:游戏税收 func (this *Player) AddServiceFee(tax int64) { if this.scene == nil || this.scene.Testing || this.scene.IsMatchScene() { //测试场不统计 return } if tax > 0 && !this.IsRob { this.serviceFee += tax } } // Statics 弃用,使用 Scene.Statistics 方法 // 个人投入产出汇总,以游戏id为key存储 // 数据用途:计算玩家赔率用,数据确保计算无误,否则可能影响玩家手牌的调控 // key: 游戏ID对应的字符串,牛牛目前用的是同一个ID,这块有待优化 // gain:输赢额,注意如果是[正值]这里一定要用税前数据,否则玩家会有数值调控优势 // 如果需要汇总gameid today的数据,可以使用game scene的GetTotalTodayDaliyGameData // Deprecated: Use Scene.Statistics instead. func (this *Player) Statics(keyGameId string, keyGameFreeId string, gain int64, isAddNum bool) { //if this.scene == nil || this.scene.Testing { //测试场|自建房和机器人不统计 // return //} // //if this.IsRob && !this.scene.IsRobFightGame() { // return //} // //if this.TodayGameData == nil { // this.TodayGameData = &model.PlayerGameCtrlData{} //} //if this.TodayGameData.CtrlData == nil { // this.TodayGameData.CtrlData = make(map[string]*model.PlayerGameStatics) //} // //var totalIn int64 //var totalOut int64 //if gain > 0 { // totalOut = gain //} else { // totalIn = -gain //} // //statics := make([]*model.PlayerGameStatics, 0, 4) ////当天数据统计 ////按场次分 //if data, ok := this.TodayGameData.CtrlData[keyGameFreeId]; ok { // statics = append(statics, data) //} else { // gs := &model.PlayerGameStatics{} // this.TodayGameData.CtrlData[keyGameFreeId] = gs // statics = append(statics, gs) //} ////按游戏分 //if data, ok := this.TodayGameData.CtrlData[keyGameId]; ok { // statics = append(statics, data) //} else { // data = &model.PlayerGameStatics{} // this.TodayGameData.CtrlData[keyGameId] = data // statics = append(statics, data) //} // ////按游戏场次进行的统计 //if data, ok := this.GDatas[keyGameFreeId]; ok { // statics = append(statics, &data.Statics) //} else { // data = &model.PlayerGameInfo{FirstTime: time.Now(), Statics: model.PlayerGameStatics{}} // this.GDatas[keyGameFreeId] = data // statics = append(statics, &data.Statics) //} //if data, ok := this.GDatas[keyGameId]; ok { // statics = append(statics, &data.Statics) //} else { // data = &model.PlayerGameInfo{FirstTime: time.Now(), Statics: model.PlayerGameStatics{}} // this.GDatas[keyGameId] = data // statics = append(statics, &data.Statics) //} // ////if !this.scene.IsPrivateScene() { //// //增加黑白名单、GM过滤,因为黑白名单过后,会导致玩家体验急剧变化 //// needStatic := this.WhiteLevel == 0 && this.WhiteFlag == 0 && this.BlackLevel == 0 && this.GMLevel == 0 //// //增加黑白名单过滤,因为黑白名单后,会导致数据出现补偿 //// if needStatic { //for _, data := range statics { // if data != nil { // data.TotalIn += totalIn // data.TotalOut += totalOut // if isAddNum { // data.GameTimes++ // if gain > 0 { // data.WinGameTimes++ // data.WinGameTimesNum++ // data.LoseGameTimesNum = 0 // } else if gain < 0 { // data.LoseGameTimes++ // data.LoseGameTimesNum++ // data.WinGameTimesNum = 0 // } else { // data.DrawGameTimes++ // data.WinGameTimesNum = 0 // data.LoseGameTimesNum = 0 // } // } // } //} // //// 黑白名单,新手,不统计到个人赔率 // ////玩家身上元数据 //this.GameTimes++ //if gain > 0 { // this.winTimes++ // this.WinTimes++ // this.WinCoin += totalOut //} else if gain < 0 { // this.lostTimes++ // this.FailTimes++ // this.FailCoin += totalIn //} else { // this.DrawTimes++ //} //// } ////} } func (this *Player) UnmarshalIParam(params []*server.PlayerIParam) { for _, p := range params { this.Iparams[int(p.GetParamId())] = p.GetIntVal() } } func (this *Player) UnmarshalSParam(params []*server.PlayerSParam) { for _, p := range params { this.sparams[int(p.GetParamId())] = p.GetStrVal() } } func (this *Player) UnmarshalCParam(params []*server.PlayerCParam) { for _, p := range params { this.cparams[p.GetStrKey()] = p.GetStrVal() } logger.Logger.Trace("(this *Player) UnmarshalCParam ", this.cparams) } func (this *Player) GetIParam(k int) int64 { if v, exist := this.Iparams[k]; exist { return v } return 0 } func (this *Player) SetIParam(k int, v int64) { this.Iparams[k] = v } func (this *Player) GetSParam(k int) string { if v, exist := this.sparams[k]; exist { return v } return "" } func (this *Player) SetSParam(k int, v string) { this.sparams[k] = v } func (this *Player) GetCoin() int64 { return this.Coin } func (this *Player) SetCoin(coin int64) { this.Coin = coin } func (this *Player) GetRankScore(rankType int32) int64 { return this.RankScore[rankType] } func (this *Player) SetRankScore(rankType int32, score int64) { this.RankScore[rankType] = score } // func (this *Player) GetStartCoin() int64 { // return this.StartCoin // } // // func (this *Player) SetStartCoin(startCoin int64) { // this.StartCoin = startCoin // } func (this *Player) GetExtraData() interface{} { return this.ExtraData } func (this *Player) SetExtraData(data interface{}) { this.ExtraData = data } func (this *Player) GetLastOPTimer() time.Time { return this.LastOPTimer } func (this *Player) SetLastOPTimer(lastOPTimer time.Time) { this.LastOPTimer = lastOPTimer } func (this *Player) GetPos() int { return this.Pos } func (this *Player) SetPos(pos int) { this.Pos = pos } func (this *Player) GetGameTimes() int32 { return this.GameTimes } func (this *Player) SetGameTimes(gameTimes int32) { this.GameTimes = gameTimes } func (this *Player) GetWinTimes() int { return this.winTimes } func (this *Player) SetWinTimes(winTimes int) { this.winTimes = winTimes } func (this *Player) GetLostTimes() int { return this.lostTimes } func (this *Player) SetLostTimes(lostTimes int) { this.lostTimes = lostTimes } func (this *Player) GetTotalBet() int64 { return this.TotalBet } func (this *Player) SetTotalBet(totalBet int64) { this.TotalBet = totalBet } func (this *Player) GetCurrentBet() int64 { return this.CurrentBet } func (this *Player) SetCurrentBet(currentBet int64) { this.CurrentBet = currentBet } func (this *Player) GetCurrentTax() int64 { return this.CurrentTax } func (this *Player) SetCurrentTax(currentTax int64) { this.CurrentTax = currentTax } func (this *Player) GetSid() int64 { return this.sid } func (this *Player) SetSid(sid int64) { this.sid = sid } func (this *Player) GetScene() *Scene { return this.scene } func (this *Player) GetGateSess() *netlib.Session { return this.gateSess } func (this *Player) SetGateSess(gateSess *netlib.Session) { this.gateSess = gateSess } func (this *Player) GetWorldSess() *netlib.Session { return this.worldSess } func (this *Player) SetWorldSess(worldSess *netlib.Session) { this.worldSess = worldSess } func (this *Player) GetCurrentCoin() int64 { return this.currentCoin } func (this *Player) SetCurrentCoin(currentCoin int64) { this.currentCoin = currentCoin } func (this *Player) GetTakeCoin() int64 { return this.takeCoin } func (this *Player) SetTakeCoin(takeCoin int64) { this.takeCoin = takeCoin } func (this *Player) GetFlag() int { return this.flag } func (this *Player) SetFlag(flag int) { this.flag = flag } func (this *Player) GetCity() string { return this.city } func (this *Player) SetCity(city string) { this.city = city } // 附加ai func (this *Player) AttachAI(ai AI) { this.ai = ai ai.SetOwner(this) ai.OnStart() } // 解除ai func (this *Player) UnattachAI() { ai := this.ai this.ai = nil ai.SetOwner(nil) ai.OnStop() } func (this *Player) RobotRandName() { if this.IsRob { //if rand.Int31n(100) < 60 { //随机昵称库里的名字 pool := srvdata.PBDB_NameMgr.Datas.GetArr() cnt := int32(len(pool)) if cnt > 0 { this.Name = pool[rand.Int31n(cnt)].GetName() } //} else { // this.Name = "Guest" //} } return } func (this *Player) RobRandVip() { if this.IsRob { dbvip := srvdata.PBDB_VIPMgr.GetData(this.VIP) if dbvip != nil { outlines := dbvip.GetRewardOutlineID() n := len(outlines) this.HeadOutLine = outlines[rand.Intn(n)] logger.Logger.Tracef("(this *Player) RobRandVip() %d HeadOutLine=%d", this.SnId, this.HeadOutLine) this.dirty = true } this.Head = rand.Int31n(common.HeadRange) //0:男 1:女 this.Sex = (this.Head%2 + 1) % 2 } } // BlackWhiteOdds 黑白名单调控概率 func (this *Player) BlackWhiteOdds(gameId int) (int32, bool) { if this.WBLevel == 0 { return 0, false } data := srvdata.PBDB_BlackWhiteMgr.GetData(int32(gameId)) if data == nil { return 0, false } var odds int32 var b bool if this.WBLevel > 0 && len(data.GetWhiteOdds()) > 0 { if int(this.WBLevel) > len(data.GetWhiteOdds()) { odds = data.GetWhiteOdds()[len(data.GetWhiteOdds())-1] b = true } else if this.WBLevel-1 >= 0 { odds = data.GetWhiteOdds()[this.WBLevel-1] b = true } } if this.WBLevel < 0 && len(data.GetBlackOdds()) > 0 { if int(-this.WBLevel) > len(data.GetBlackOdds()) { odds = data.GetBlackOdds()[len(data.GetBlackOdds())-1] b = true } else if -this.WBLevel-1 >= 0 { odds = data.GetBlackOdds()[-this.WBLevel-1] b = true } } //logger.Logger.Tracef("TienLenSceneData snid(%v) 黑白名单调控 是否启用:%v WBLevel:%v config:%v 概率:%v", this.SnId, b, this.WBLevel, data, odds) this.TestLog = append(this.TestLog, fmt.Sprintf("黑白名单调控 是否启用:%v WBTotalOut:%v WBTotalIn:%v WBCoinLimit:%v WBLevel:%v config:%v 概率:%v", b, this.WBCoinTotalOut, this.WBCoinTotalIn, this.WBCoinLimit, this.WBLevel, data, odds)) return odds, b } // NoviceOdds 新手补偿概率 func (this *Player) NoviceOdds(gameId int) (int32, bool) { data := srvdata.PBDB_NewPlayerMgr.GetData(int32(gameId)) if data == nil { return 0, false } if model.GameParamData.CloseNovice || common.InSliceInt(model.GameParamData.CloseNoviceGame, gameId) { return 0, false } keyNoviceGameId := common.GetKeyNoviceGameId(gameId) var b1, b2 bool var times, targetTimes int64 var winCoin, targetWinCoin int64 switch data.GetCondition1() { case 1: // 游戏次数 m := this.GDatas[keyNoviceGameId] if m == nil { b1 = true } else { b1 = m.Statics.GameTimes < data.GetConditionValue1() times = m.Statics.GameTimes } targetTimes = data.GetConditionValue1() case 2: // gameId输赢金额 m := this.GDatas[keyNoviceGameId] if m == nil { b1 = true } else { b1 = m.Statics.TotalOut-m.Statics.Tax-m.Statics.TotalIn < data.GetConditionValue1() winCoin = m.Statics.TotalOut - m.Statics.TotalIn } targetWinCoin = data.GetConditionValue1() } switch data.GetCondition2() { case 1: // 游戏次数 m := this.GDatas[keyNoviceGameId] if m == nil { b2 = true } else { b2 = m.Statics.GameTimes < data.GetConditionValue2() times = m.Statics.GameTimes } targetTimes = data.GetConditionValue2() case 2: // gameId输赢金额 m := this.GDatas[keyNoviceGameId] if m == nil { b2 = true } else { b2 = m.Statics.TotalOut-m.Statics.Tax-m.Statics.TotalIn < data.GetConditionValue2() winCoin = m.Statics.TotalOut - m.Statics.TotalIn } targetWinCoin = data.GetConditionValue2() } switch data.GetBond() { case 1: // or b1 = b1 || b2 case 2: // and b1 = b1 && b2 } var odds int if b1 { switch data.GetAddType() { case 1: // 游戏次数 odds = common.SliceMaxValue([]int{int(data.GetAddMin()), int(data.GetAddMax() - int64(float64(times)/float64(targetTimes)*float64(data.GetAddMax()-data.GetAddMin())))}) case 2: // gameId输赢金额 odds = common.SliceMaxValue([]int{int(data.GetAddMin()), int(data.GetAddMax() - int64(float64(winCoin)/float64(targetWinCoin)*float64(data.GetAddMax()-data.GetAddMin())))}) } odds = common.SliceMinValue([]int{int(data.GetAddMax()), odds}) } //logger.Logger.Tracef("TienLenSceneData snid(%v) 新手调控 是否启用:%v times:%v winCoin:%v config:%v 概率:%v", this.SnId, b1, times, winCoin, data, odds) this.TestLog = append(this.TestLog, fmt.Sprintf("新手调控 是否启用:%v times:%v winCoin:%v config:%v 概率:%v", b1, times, winCoin, data, odds)) return int32(odds), b1 } // 增加玩家经验 func (this *Player) AddPlayerExp(exp int64) bool { this.Exp += exp if this.Exp >= int64(math.MaxInt64) { this.Exp = int64(math.MaxInt64) } maxExp := srvdata.PBDB_PlayerExpMgr.Datas.Arr[len(srvdata.PBDB_PlayerExpMgr.Datas.Arr)-1].Exp if this.Exp > int64(maxExp) { this.Exp = int64(maxExp) } //oldLevel := this.Level //获取等级 for _, playerExp := range srvdata.PBDB_PlayerExpMgr.Datas.Arr { if this.Exp >= int64(playerExp.Exp) { this.Level = int64(playerExp.Id) } else { break } } pack := &player.SCPlayerUpLevel{ Level: this.Level, Exp: this.Exp, } //通知客户端玩家提升等级 this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PlayerUpLevel), pack) return true } // 解锁炮倍 func (this *Player) UnPlayerPowerEx(power int64) { logger.Logger.Tracef("解锁炮倍 当前最大解锁炮倍:%v,要解锁的炮倍:%v", this.UnMaxPower, power) if this.UnPlayerPower(power) { pack := &player.SCPlayerUnPower{ UnMaxpower: power, } this.UnMaxPower = power this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PlayerUnPower), pack) logger.Logger.Tracef("通知客户端解锁最大炮倍,snid = %v,power = %v", this.SnId, power) } } // 解锁炮台 func (this *Player) UnPlayerPowerListEx(powerId int32) { data := srvdata.PBDB_ArtillerySkinMgr.GetData(powerId) if data == nil { return } if this.UnPlayerPowerList(powerId) { //通知客户端解锁炮台 pack := &player.SCPlayerUnPowerList{ UnPowerList: powerId, } this.SendToClient(int(player.PlayerPacketID_PACKET_SC_PlayerUnPowerList), pack) logger.Logger.Trace("通知客户端解锁炮台 snid = %v,解锁的炮台:%v,当前已有的炮台 = %v", this.SnId, powerId, this.PowerList) } return } // 获取周卡权益 // typeId : 1-破产救济金领取翻倍 2-排位赛积分提升5% func (this *Player) GetWeekCardPrivilege(typeId int32) bool { logger.Logger.Trace("玩家请求获取周卡权益!") now := time.Now().Unix() for id, endTime := range this.WeekCardTime { if endTime > now { data := srvdata.PBDB_GiftCardMgr.GetData(id) for _, equity := range data.GetEquity() { if equity == typeId { return true } } } } return false } // UpdatePigBankCoin 更新玩家存钱罐 func (this *Player) UpdatePigBankCoin(gainTexCoin int64) { if this.IsRobot() { return } if this.PlayerData.WelfData == nil || this.PlayerData.WelfData.PigBank == nil { return } fGetPropValue := func(propName string) int64 { pool := srvdata.PBDB_Pigbank_PropMgr.Datas.GetArr() for _, PropItem := range pool { if PropItem.PorpName == propName { return int64(PropItem.PropValue) } } return 0 } BankCoinMax := int64(0) for _, data := range srvdata.PBDB_PigBank_DiamondMgr.Datas.GetArr() { if this.WelfData.PigBank.DayBuyTimes+1 >= data.BuyCountMin && this.WelfData.PigBank.DayBuyTimes+1 <= data.BuyCountMax { BankCoinMax = int64(data.MaxGold) break } } pack := &player.SCPigBankCoin{} if gainTexCoin < 0 { LoseCoinRate := fGetPropValue("LoseCoinRate") pack.AddBankCoin = int64(math.Abs(math.Ceil(float64(gainTexCoin) * float64(LoseCoinRate) / 100.0))) } if gainTexCoin > 0 { WinCoinRate := fGetPropValue("WinCoinRate") pack.AddBankCoin = int64(math.Ceil(float64(gainTexCoin) * float64(WinCoinRate) / 100.0)) } this.WelfData.PigBank.BankCoin += pack.AddBankCoin if this.WelfData.PigBank.BankCoin > BankCoinMax { this.WelfData.PigBank.BankCoin = BankCoinMax } pack.BankCoinMax = BankCoinMax pack.BankCoin = this.WelfData.PigBank.BankCoin logger.Logger.Trace("(this *TienLenPlayerData) UpdatePigbankCoin player SnId:", this.SnId, ";pack: ", pack, ";gainTexCoin: ", gainTexCoin) this.SendToClient(int(player.PlayerPacketID_PACKET_SCPigBankCoin), pack) } // UpdateBuyRecTimeItem 购买记牌器后更新时间、钻石 func (this *Player) UpdateBuyRecTimeItem(expireTime, diamond int64) { this.Diamond = diamond this.ItemRecExpireTime = expireTime } // 宠物技能使用 func (this *Player) PetUseSkill() bool { data := srvdata.PBDB_PetSkillMgr.Datas.GetArr() for _, info := range this.Pets.SkillInfo { for skillId, skillLevel := range info { var skillInfo = &server.DB_PetSkill{} for _, info := range data { if info.SkillId == skillId && info.SkillLevel == skillLevel && info.SkillType == 1 { skillInfo = info break } } if skillInfo == nil { return false } random := rand.Intn(100) + 1 logger.Logger.Trace("宠物技能抵挡炸弹,随机到的值 = ", random, " 技能id = ", skillId, " 技能等级 = ", skillLevel, " 技能值 = ", skillInfo.SKillValue) if random <= int(skillInfo.SKillValue) { logger.Logger.Trace("炸弹,宠物技能抵挡成功!") return true } } } return false } // GetSkillAdd 获取技能加成 // id 技能id func (this *Player) GetSkillAdd(id int32) int32 { return this.GetSkillAdd2(id, ConfigMgrInst) } // AddItems 添加道具 // 增加或减少道具 // 同步到 worldsrv func (this *Player) AddItems(args *model.AddItemParam) { pack := &server.PlayerChangeItems{ SnId: args.P.SnId, } for _, v := range args.Change { item := srvdata.GameItemMgr.Get(this.Platform, v.ItemId) if item == nil { continue } if v.ItemNum < 0 && this.Items[v.ItemId] < -v.ItemNum { v.ItemNum = -this.Items[v.ItemId] } if v.ItemNum == 0 { continue } this.Items[v.ItemId] += v.ItemNum if !args.NoLog { logType := 0 if v.ItemNum < 0 { logType = 1 } LogChannelSingleton.WriteLog(model.NewItemLogEx(model.ItemParam{ Platform: this.Platform, SnId: this.SnId, LogType: int32(logType), ItemId: v.ItemId, ItemName: item.Name, Count: v.ItemNum, Remark: args.Remark, TypeId: args.GainWay, GameId: args.GameId, GameFreeId: args.GameFreeId, Cost: args.Cost, })) } pack.Items = append(pack.Items, &server.Item{ Id: v.ItemId, Num: v.ItemNum, }) } if len(pack.Items) > 0 { this.SendToWorld(int(server.SSPacketID_PACKET_PlayerChangeItems), pack) logger.Logger.Tracef("PlayerChangeItems: %v", pack) } } //func (this *Player) ReceiveAddItems(items []*model.Item) { // for _, v := range items { // item := srvdata.GameItemMgr.Get(this.Platform, v.ItemId) // if item == nil { // continue // } // if v.ItemNum < 0 && this.Items[v.ItemId] < -v.ItemNum { // v.ItemNum = -this.Items[v.ItemId] // } // if v.ItemNum == 0 { // continue // } // this.Items[v.ItemId] += v.ItemNum // logger.Logger.Tracef("ReceiveAddItems snid:%v, item:%v, num:%v change:%v", this.SnId, v.ItemId, this.Items[v.ItemId], v.ItemNum) // } //}