game_sync/gamesrv/base/player.go

1364 lines
39 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package base
import (
"fmt"
"github.com/jinzhu/now"
"math"
"math/rand"
"time"
rawproto "google.golang.org/protobuf/proto"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/netlib"
"mongo.games.com/goserver/core/timer"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/mq"
"mongo.games.com/game/proto"
"mongo.games.com/game/protocol/player"
"mongo.games.com/game/protocol/server"
"mongo.games.com/game/srvdata"
)
// 对应到客户端的一个玩家对象.
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.WGPlayerInfo
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),
}
//todo 初始化
p.WGPlayerInfo = model.WGPlayerInfo{
PlayerData: &model.PlayerData{
GDatas: make(map[string]*model.PlayerGameInfo),
ShopTotal: make(map[int32]*model.ShopTotal),
ShopLastLookTime: make(map[int32]int64),
IsFoolPlayer: make(map[string]bool),
},
GameData: make(map[string]*model.PlayerGameData),
}
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_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) {
// 防止参数遗漏
for k, v := range this.GameData {
if v.SnId == 0 {
v.SnId = this.SnId
}
if v.Platform == "" {
v.Platform = this.Platform
}
if v.Id == "" {
v.Id = k
}
}
d, e = netlib.Gob.Marshal(&this.WGPlayerInfo)
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.WGPlayerInfo)
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
mq.Write(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),
Tp: common.PlayerChangeTypeCoin,
}
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),
Tp: common.PlayerChangeTypeNum,
}
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
mq.Write(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),
Tp: common.PlayerChangeTypeCoin,
}
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
}
}
type ReportGameEventParam struct {
Tax int64 // 税收
Change int64 // 净输赢,正负值,不带税收
In, Out int64 // 投入,产出(税前)
GameTime int64 // 游戏时长,秒
}
func (this *Player) ReportGameEvent(param *ReportGameEventParam) {
// 记录玩家 首次参与该场次的游戏时间 游戏次数
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
}
isNew := int32(0)
tCreateDay := now.New(this.CreateTime.Local()).BeginningOfDay()
if now.BeginningOfDay().Equal(tCreateDay) {
isNew = 1
}
if param.GameTime < 0 {
param.GameTime = int64(time.Now().Sub(this.scene.GameNowTime).Seconds())
}
if param.GameTime < 0 {
param.GameTime = 0
}
log := &model.PlayerGameRecEvent{
Platform: this.Platform,
RecordId: this.scene.GetRecordId(),
SnId: this.GetSnId(),
Channel: this.Channel,
ChannelId: this.ChannelId,
City: this.City,
OS: this.DeviceOS,
GameId: this.scene.GameId,
ModeId: this.scene.GameMode,
Tax: param.Tax,
Amount: param.Change,
CreateTime: this.CreateTime.Unix(),
CreateDayTime: tCreateDay.Unix(),
Out: param.Out,
In: param.In,
IsNew: isNew,
GameFreeID: this.scene.GetGameFreeId(),
GamingTime: int32(param.GameTime),
FirstTime: gameFirstTime.Unix(),
PlayTimes: gameTimes,
FirstGameTime: gameFreeFirstTime.Unix(),
PlayGameTimes: gameFreeTimes,
LastLoginTime: this.LastLoginTime.Unix(),
DeviceId: this.DeviceId,
}
mq.Write(log, mq.BackGameRecord)
}
// 汇总玩家该次游戏总产生的税收
// 数据用途: 平台和推广间分账用,确保数据计算无误,
// 注意:该税收不包含俱乐部的抽水
// 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) {
args.IsGame = true
changeItem := map[int32]int64{}
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
changeItem[v.ItemId] += v.ItemNum
}
if len(changeItem) > 0 {
args.Change = args.Change[:0]
for k, v := range changeItem {
args.Change = append(args.Change, &model.Item{
ItemId: k,
ItemNum: v,
})
}
b, err := netlib.Gob.Marshal(args)
if err != nil {
logger.Logger.Errorf("道具变更日志序列化失败 %v", err)
}
pack := &server.PlayerChangeItems{
Data: b,
}
this.SendToWorld(int(server.SSPacketID_PACKET_PlayerChangeItems), pack)
logger.Logger.Tracef("PlayerChangeItems: %v", args)
}
}
//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)
// }
//}