package main

import (
	"bytes"
	"crypto/md5"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"io"
	"math"
	"math/rand"
	"os"
	"slices"
	"sort"
	"strconv"
	"time"

	"github.com/globalsign/mgo/bson"
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/netlib"
	"mongo.games.com/goserver/core/task"
	"mongo.games.com/goserver/srvlib"
	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/bag"
	hall_proto "mongo.games.com/game/protocol/gamehall"
	login_proto "mongo.games.com/game/protocol/login"
	msg_proto "mongo.games.com/game/protocol/message"
	player_proto "mongo.games.com/game/protocol/player"
	"mongo.games.com/game/protocol/rankmatch"
	server_proto "mongo.games.com/game/protocol/server"
	shop_proto "mongo.games.com/game/protocol/shop"
	webapi_proto "mongo.games.com/game/protocol/webapi"
	"mongo.games.com/game/srvdata"
	"mongo.games.com/game/worldsrv/internal"
)

// 对应到客户端的一个玩家对象.

const (
	PlayerStateOnline int = iota
	PlayerStateOffline
)

const (
	UpdateField_Coin int64 = 1 << iota
	UpdateField_SafeBoxCoin
	UpdateField_VIP
	UpdateField_CoinPayTotal
	UpdateField_TotalConvertibleFlow
	UpdateField_Ticket
	UpdateField_Grade
	UpdateField_Diamond
	UpdateField_VCoin
	UpdateField_ChessGrade
	UpdateField_RankScore
	UpdateField_PhoneScore
	UpdateField_InviteScore
)

const (
	CurrencyType_Card int32 = iota
	CurrencyType_Coin
	CurrencyType_Money
	CurrencyType_RMB
)

var VIP_RandWeight = []int64{30, 30, 20, 10, 5, 5}

type ErrorString struct {
	code string
}

func (this *ErrorString) Error() string {
	return this.code
}

type Player struct {
	*model.PlayerData                                   //po 持久化对象
	diffData                  model.PlayerDiffData      //差异数据
	gateSess                  *netlib.Session           //所在GateServer的session
	scene                     *Scene                    //当前所在个Scene
	thrscene                  int                       //是否在三方
	sid                       int64                     //对应客户端的sessionId
	state                     int                       //玩家状态 PlayerStateOnline PlayerStateOffline
	lastSaved                 time.Time                 //最后保存的时间
	dirty                     bool                      //脏标记
	pos                       int                       //位置
	msgs                      map[string]*model.Message //
	beUnderAgent              bool                      //是否隶属于代理
	lastSceneId               map[int32][]int32         //上一个房间id；gamefreeid:房间号
	ollenSecs                 int32                     //在线时长
	currClubId                int32                     //当前所在的俱乐部id
	takeCoin                  int64                     //携带金币
	sceneCoin                 int64                     //房间里当前的金币量
	isNewbie                  bool                      //是否是新用户
	applyPos                  int32                     //申请的场景位置
	flag                      int32                     //Game服务器的用户状态
	hallId                    int32                     //所在游戏大厅
	changeIconTime            time.Time                 //上次修改头像时间
	enterts                   time.Time                 //进入时间
	lastChangeScene           time.Time                 //上次换桌时间
	isAudience                bool                      //是否是观众
	customerToken             string                    //客服会话token
	isDelete                  bool                      //是否已删档用户
	thridBalanceRefreshReqing bool                      //玩家请求刷新三方金额进行中
	thridBalanceReqIsSucces   bool                      //三方请求刷新成功
	params                    *model.PlayerParams       //客户端登陆游戏带上来的临时参数
	exchangeState             bool                      //订单操作状态
	lastOnDayChange           time.Time
	lastOnWeekChange          time.Time
	lastOnMonthChange         time.Time
	//例如["WWG平台"][true:已经刷新过不用再次刷新，false:未知需要刷新]
	//注意：该数据不会落地到mgo,游服第一次启动的时候会请求全部三方刷新余额，之后就会根据标记来进行刷新。
	//确保thirdBalanceRefreshMark只在主协程里面操作
	thirdBalanceRefreshMark map[string]bool
	EnterCoinSceneQueueTs   int64
	CoinSceneQueueRound     int32
	CoinSceneQueue          *CoinScenePool
	EnterQueueTime          time.Time //进入队列的时间
	//比赛
	cparams map[string]string //平台登陆数据	"name", "head", "geo-info", "lang", "ip"
	Iparams map[int]int64     //整形参数
	sparams map[int]string    //字符参数
	//用户登录时获取 单用户活动开关控制
	layered map[int]bool //true 为关 false为开
	//用户分层ids
	layerlevels []int            //缓存玩家身上所有分层数据
	miniScene   map[int32]*Scene //当前所在个Scene
	leavechan   chan int

	// 比赛环境
	matchCtx *PlayerMatchContext
	// 在线记录
	onlineLog *model.OnlineLog
	// 数据埋点
	DeviceName   string // 设备名称
	PackageName  string // 包名
	AppVersion   string // app版本
	BuildVersion string // app构建版本
	AppChannel   string // app渠道(玩家本次登录使用的包的渠道类型，换登录包，这个值也会变;玩家model.PlayerData存储的渠道是玩家第一次登录的渠道，不会修改)
	// 最后玩的游戏id
	LastGameId int
	GameID     []int32 // 最近三天玩的游戏
	InviteNum  int32   // 邀请人数
}

func NewPlayer(sid int64, pd *model.PlayerData, s *netlib.Session) *Player {
	// 玩家数据初始化
	p := &Player{
		PlayerData:              pd,
		sid:                     sid,
		gateSess:                s,
		msgs:                    make(map[string]*model.Message),
		cparams:                 make(map[string]string),
		Iparams:                 make(map[int]int64),
		sparams:                 make(map[int]string),
		pos:                     -1,
		beUnderAgent:            pd.BeUnderAgentCode != "",
		thirdBalanceRefreshMark: make(map[string]bool),
		layered:                 make(map[int]bool),
		miniScene:               make(map[int32]*Scene),
	}
	if p.IsRob {
		p.RobotRandName()
	}
	if p.init() {
		return p
	}
	return nil
}

// 玩家数据初始化
func (this *Player) init() bool {
	this.SetOnline()
	this.isNewbie = this.CreateTime == this.LastLoginTime
	this.applyPos = -1
	return true
}

func (this *Player) GenCustomerToken() string {
	if this.customerToken != "" {
		return this.customerToken
	}

	raw := fmt.Sprintf("%v%v%v%v%v", this.SnId, this.AccountId, this.sid, common.GetAppId(), time.Now().UnixNano())
	h := md5.New()
	io.WriteString(h, raw)
	token := hex.EncodeToString(h.Sum(nil))
	return token
}

func (this *Player) SyncBagData(itemInfo []*bag.ItemInfo) {
	pack := &bag.SCSyncBagData{
		Infos: itemInfo,
	}
	this.SendToClient(int(bag.SPacketID_PACKET_SC_SYNCBAGDATA), pack)
	logger.Logger.Tracef("背包数据变更(%v): %v", this.SnId, pack)
}

// SendToClient 给客户端发消息，玩家需要在线
func (this *Player) SendToClient(packetid int, rawpack interface{}) bool {
	if this.IsOffline() {
		logger.Logger.Trace("Player if offline.")
		return false
	}

	return this.SendRawToClientIncOffLine(this.sid, this.gateSess, packetid, rawpack)
}

// SendRawToClientIncOffLine 给客户端发消息，不关心是否在线
func (this *Player) SendRawToClientIncOffLine(sid int64, gateSess *netlib.Session, packetid int, rawpack interface{}) bool {
	if gateSess == nil {
		logger.Logger.Tracef("[%v] sess == nil ", this.SnId, packetid)
		return false
	}
	if rawpack == nil {
		logger.Logger.Trace(" rawpack == nil ")
		return false
	}

	return common.SendToGate(sid, packetid, rawpack, gateSess)
}

func (this *Player) SendToGame(packetid int, rawpack interface{}) bool {
	if this.scene == nil || this.scene.gameSess == nil || this.scene.gameSess.Session == nil {
		logger.Logger.Tracef("[%v] sess == nil ", this.Name)
		return false
	}
	if rawpack == nil {
		logger.Logger.Trace(" rawpack == nil ")
		return false
	}

	return this.scene.SendToGame(packetid, rawpack)
}

func (this *Player) LoadAfter() {
	var replays []*internal.PlayerLoadReplay
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		for _, v := range internal.GetPlayerLoads() {
			replays = append(replays, v.LoadAfter(this.Platform, this.SnId))
		}
		return nil
	}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
		if len(replays) != len(internal.GetPlayerLoads()) {
			return
		}
		for k, v := range internal.GetPlayerLoads() {
			if v == nil || replays[k] == nil {
				continue
			}
			v.CallbackAfter(replays[k])
		}
	})).StartByFixExecutor(fmt.Sprintf("Player%v", this.SnId))
}

func (this *Player) OnLogined() {
	logger.Logger.Tracef("(this *Player) OnLogined() %v", this.SnId)
	this.lastSaved = time.Now()
	isFirstLogin := false
	if this.CreateTime.Unix() > this.LastLogoutTime.Unix() {
		isFirstLogin = true
	}

	// 跨天业务处理
	tNow := time.Now()
	tLastLogout := this.PlayerData.LastLogoutTime
	this.PlayerData.LastLoginTime = tNow
	this.PlayerData.LastLogoutTime = tNow
	this.dirty = true
	if !common.InSameDay(tNow, tLastLogout) { //跨天
		logger.Logger.Infof("(this *Player) OnLogined(%v) inSameDay LastLogoutTime(%v)", this.SnId, tLastLogout)
		isContinueDay := common.IsContinueDay(tNow, tLastLogout)
		// 计算跨了多少天
		var t int
		t1 := tLastLogout
		t2 := tNow
		out := time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, t1.Location())
		in := time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, t2.Location())
		t = int(math.Floor(in.Sub(out).Hours() / 24))
		this.OnDayTimer(true, isContinueDay, t)
	}
	// 跨月
	inSameMoney := common.InSameMonth(tNow, tLastLogout)
	if !inSameMoney {
		this.OnMonthTimer()
	}
	// 跨周
	inSameWeek := common.InSameWeek(tNow, tLastLogout)
	if !inSameWeek {
		this.OnWeekTimer()
	}

	this.SetOnline()

	//测试用
	if !this.IsRob {
		old := this.VIP
		this.VIP = this.GetVIPLevel(this.CoinPayTotal)
		if old != this.VIP {
			this.dirty = true
		}
	} else {
		this.VIP = rand.Int31n(6) + 1
		//机器人随机vip和头像
		this.RobRandVip()
	}

	this.VipExtra = VipMgrSington.GetVipPointsExtra(this.Platform, this.VIP)

	// 头像决定性别
	this.Sex = (this.Head%2 + 1) % 2

	// 初始化差异数据
	this.BackDiffData()

	this.BindGroupTag([]string{this.Platform})

	PlatformMgrSingleton.PlayerLogin(this)

	gameStateMgr.PlayerClear(this)

	//玩家登录事件
	FirePlayerLogined(this)

	this.RandRobotExData()

	this.SendJackPotInit()

	this.GetPayGoodsInfo()

	if !this.IsRob {
		PlayerOnlineSington.Check = true

		this.LoadMessage(tLastLogout.Unix(), isFirstLogin, !inSameWeek)

		//登录次数
		this.LoginTimes++

		//登录事件
		this.ReportLoginEvent()

		//抽奖次数兼容老玩家
		if !this.InitLotteryStatus && WelfareMgrSington.GetPhoneLotteryStatus(this.Platform) == WelfareOpen {
			this.addLotteryCount(20)
			this.InitLotteryStatus = true
			this.dirty = true
			LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(this.SnId, this.Platform, "", 3, 20, 5, 0))
		}

		//登录日志
		logState := LoginStateMgrSington.GetLoginStateBySid(this.sid)
		var clog *model.ClientLoginInfo
		if logState != nil {
			clog = logState.clog
		}
		LogChannelSingleton.WriteLog(model.NewLoginLog(this.SnId, common.LoginLogTypeLogin, this.Tel, this.Ip,
			this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.City, clog, this.GetTotalCoin(), 0, 0,
			this.DeviceName, this.PackageName, this.AppVersion, this.BuildVersion, this.AppChannel))

		this.OnlineLogLogin()

		this.SendToRepSrv(this.PlayerData)

		//七日活动
		ActSignMgrSington.OnPlayerLogin(this)

		//红点检测
		this.CheckShowRed()

		TaskSubjectSingleton.Touch(common.TaskTypeLogin, &TaskData{SnId: this.SnId, Num: 1}) // 登录游戏

		this.LoadAfter()
	}
}

func (this *Player) OnRehold() {
	logger.Logger.Tracef("(this *Player) OnRehold() %v", this.SnId)
	this.SetOnline()

	var gameid int
	if this.scene != nil && this.scene.gameSess != nil {
		//if this.scene.sceneId == SceneMgrSingleton.GetDgSceneId() {
		//	// DG特殊处理
		//	//如果是之前进入的是DG游戏，就退出DG游戏
		//	this.DgGameLogout()
		//} else {
		// 告诉游戏服务玩家重连
		var gateSid int64
		if this.gateSess != nil {
			if srvInfo, ok := this.gateSess.GetAttribute(srvlib.SessionAttributeServerInfo).(*srvlibproto.SSSrvRegiste); ok && srvInfo != nil {
				sessionId := srvlib.NewSessionIdEx(srvInfo.GetAreaId(), srvInfo.GetType(), srvInfo.GetId(), 0)
				gateSid = sessionId.Get()
			}
		}
		pack := &server_proto.WGPlayerRehold{
			Id:      proto.Int32(this.SnId),
			Sid:     proto.Int64(this.sid),
			SceneId: proto.Int(this.scene.sceneId),
			GateSid: proto.Int64(gateSid),
		}
		proto.SetDefaults(pack)
		this.SendToGame(int(server_proto.SSPacketID_PACKET_WG_PLAYERREHOLD), pack)
		logger.Logger.Tracef("WG PlayerRehold: %v", pack)
		//}
		gameid = this.scene.gameId
	}

	this.BindGroupTag([]string{this.Platform})

	//登录事件
	this.ReportLoginEvent()

	PlatformMgrSingleton.PlayerLogin(this)

	gameStateMgr.PlayerClear(this)

	//玩家重连事件
	FirePlayerRehold(this)

	FriendMgrSington.ApplyList(this.Platform, this.SnId)
	FriendUnreadMgrSington.CheckSendFriendUnreadData(this.Platform, this.SnId)

	//七日活动.
	ActSignMgrSington.OnPlayerLogin(this)

	this.CheckShowRed()

	this.SendJackPotInit()

	this.GetPayGoodsInfo()

	RankMgrSingleton.CheckShowRed(this.SnId)

	if !this.IsRob {
		PlayerOnlineSington.Check = true

		// 记录重连日志
		logState := LoginStateMgrSington.GetLoginStateBySid(this.sid)
		var clog *model.ClientLoginInfo
		if logState != nil {
			clog = logState.clog
		}
		LogChannelSingleton.WriteLog(model.NewLoginLog(this.SnId, common.LoginLogTypeRehold, this.Tel, this.Ip,
			this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.City, clog, this.GetTotalCoin(),
			gameid, 0, this.DeviceName, this.PackageName, this.AppVersion, this.BuildVersion, this.AppChannel))

		this.OnlineLogRehold()
	}
}

func (this *Player) CheckShowRed() {
	this.MessageShowRed()

	//商城红点
	ShopMgrSington.ShopCheckShowRed(this)

	//数据依赖于背包数据  放入加载背包数据之后执行
	//PetMgrSington.CheckShowRed(this)

	//福利红点
	WelfareMgrSington.WelfareShowRed(this)
}

// 为了worldsrv和gamesrv上机器人信息一致
func (this *Player) RandRobotExData() {
	if !this.IsRob {
		return
	}
	// 角色
	datas := srvdata.PBDB_Game_IntroductionMgr.Datas.GetArr()
	if datas != nil {
		//随机
		//var roles = []int32{}
		//for _, data := range datas {
		//    if data.Type == 1 { //角色
		//        roles = append(roles, data.Id)
		//    }
		//}
		//if roles != nil && len(roles) > 0 {
		//    randId := common.RandInt32Slice(roles)
		//    this.Roles = new(model.RolePetInfo)
		//    this.Roles.ModUnlock = make(map[int32]int32)
		//    this.Roles.ModUnlock[randId] = 1
		//    this.Roles.ModId = randId
		//}
		//女8男2
		rand := common.RandInt(100)
		randId := int32(2000001)
		if rand < 20 {
			randId = 2000002
		}
		this.Roles = new(model.RolePetInfo)
		this.Roles.ModUnlock = make(map[int32]int32)
		this.Roles.ModUnlock[randId] = 1
		this.Roles.ModId = randId
	}
	// 宠物
	//    datas := srvdata.PBDB_Game_IntroductionMgr.Datas.GetArr()
	//    if datas != nil {
	//        var pets = []int32{}
	//        for _, data := range datas {
	//            if data.Type == 2 { //宠物
	//                pets = append(pets, data.Id)
	//            }
	//        }
	//        if pets != nil && len(pets) > 0 {
	//            randId := common.RandInt32Slice(pets)
	//            this.Pets = new(model.RolePetInfo)
	//            this.Pets.ModUnlock = make(map[int32]int32)
	//            this.Pets.ModUnlock[randId] = 1
	//            this.Pets.ModId = randId
	//        }
	//    }
}

// SendGameConfig 玩家断线重连时，获取玩家所有游戏的配置信息
func (this *Player) SendGameConfig(gameId int32, plf, chl string) {
	pack := &hall_proto.SCGetGameConfig{
		GameId: gameId,
	}

	gps := PlatformMgrSingleton.GetGameFrees(this.Platform)
	for _, v := range gps {
		if v.Status && PlatformMgrSingleton.GameStatus[v.DbGameFree.Id] {
			if v.DbGameFree.GetGameRule() != 0 && v.DbGameFree.GetGameId() == gameId {
				// 场次配置
				lgc := &hall_proto.GameConfig1{
					LogicId:         proto.Int32(v.DbGameFree.Id),
					LimitCoin:       proto.Int64(v.DbGameFree.GetLimitCoin()),
					MaxCoinLimit:    proto.Int64(v.DbGameFree.GetMaxCoinLimit()),
					BaseScore:       proto.Int32(v.DbGameFree.GetBaseScore()),
					BetScore:        proto.Int32(v.DbGameFree.GetBetLimit()),
					OtherIntParams:  v.DbGameFree.GetOtherIntParams(),
					MaxBetCoin:      v.DbGameFree.GetMaxBetCoin(),
					MatchMode:       proto.Int32(v.DbGameFree.GetMatchMode()),
					Status:          v.Status,
					SceneType:       v.DbGameFree.GetSceneType(),
					ChessGradeLimit: v.DbGameFree.GetChessGradeLimit(),
					RankType:        v.DbGameFree.GetRankType(),
					SceneAdd:        v.DbGameFree.GetSceneAdd(),
				}
				// 排位场参数
				if v.DbGameFree.GetRankType() > 0 {
					lgc.RankType = v.DbGameFree.GetRankType()
					lgc.SceneAdd = v.DbGameFree.GetSceneAdd()
				}

				pack.GameCfg = append(pack.GameCfg, lgc)
			}
		}
	}

	// 游戏配置
	if common.IsChess(int(gameId)) {
		cfg := ChessRankMgrSington.GetChessRankConfig(this.GetPlatform().Name, gameId)
		for _, v := range cfg.GetDatas() {
			pack.ChessRanks = append(pack.ChessRanks, &hall_proto.ChessRankInfo{
				Score: v.Score,
				Name:  v.Name,
			})
		}
	}

	this.SendToClient(int(hall_proto.GameHallPacketID_PACKET_SC_GETGAMECONFIG), pack)
	logger.Logger.Tracef("SendGameConfig:%v", pack)
}

func (this *Player) LoadMessage(lastLogoutTime int64, isFirstLogin, isSkipWeek bool) {
	task.New(nil,
		task.CallableWrapper(func(o *basic.Object) interface{} {
			//msgs, err := model.GetMessageByNotState(this.SnId, model.MSGSTATE_REMOVEED)
			//if err == nil {
			//	return msgs
			//} else {
			//	logger.Logger.Warnf("[%v] LoadMessage err:%v", this.Name, err)
			//}
			msgs, err := model.GetMessage(this.Platform, this.SnId) // model.GetNotDelMessage(this.Platform, this.SnId)
			if err == nil {
				return msgs
			} else {
				logger.Logger.Warnf("[%v] LoadMessage err:%v", this.Name, err)
			}
			return nil
		}),
		task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
			if data != nil {
				if msgs, ok := data.([]model.Message); ok {
					for i := 0; i < len(msgs); i++ {
						this.msgs[msgs[i].Id.Hex()] = &msgs[i]
					}
				}
				//跨周 邮件>0
				if isSkipWeek && len(this.msgs) > 0 {
					//过期邮件处理
					for key, msg := range this.msgs {
						if msg.AttachState == model.MSGATTACHSTATE_DEFAULT && msg.Ticket > 0 {
							this.TicketTotalDel += msg.Ticket
							this.DelMessage(key, 1)
						}
					}
					this.dirty = true
				}

				var dbMsgs []*model.Message

				//第一次登录需要屏蔽订阅的邮件
				if !isFirstLogin {
					msgs := MsgMgrSington.GetSubscribeMsgs(this.Platform, lastLogoutTime)
					for _, msg := range msgs {
						bHasAddToPlayer := false
						for _, pMsg := range this.msgs {
							if pMsg.Pid == msg.Id.Hex() {
								bHasAddToPlayer = true
								break
							}
						}
						if bHasAddToPlayer == false {
							newMsg := model.NewMessage(msg.Id.Hex(), msg.SrcId, "", this.SnId, msg.MType, msg.Title,
								msg.Content, msg.Coin, msg.Diamond, model.MSGSTATE_UNREAD, msg.CreatTs, msg.AttachState,
								msg.GiftId, msg.Params, msg.Platform, msg.ShowId)
							dbMsgs = append(dbMsgs, newMsg)
						}
					}
				}

				if len(dbMsgs) != 0 {
					task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
						return model.InsertMessage(this.Platform, dbMsgs...)
					}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
						if data == nil {
							for _, msg := range dbMsgs {
								bHasAddToPlayer := false
								for _, pMsg := range this.msgs {
									if pMsg.Pid == msg.Id.Hex() {
										bHasAddToPlayer = true
										break
									}
								}
								if bHasAddToPlayer == false {
									this.AddMessage(msg)
								}
							}
							// 邮件由客户端拉取
							//this.SendMessage()
						}
					}), "InsertMessage").StartByFixExecutor("logic_message")
				} else {
					// this.SendMessage()
				}
				if len(this.msgs) > model.MSG_MAX_COUNT {
					maxTs := int64(0)
					for _, m := range this.msgs {
						if m.CreatTs > maxTs {
							maxTs = m.CreatTs
						}
					}
					this.verifyMessage(maxTs)
				}
			}
		}), "GetMessage").StartByFixExecutor("logic_message")
}

func (this *Player) SendMessage(showId int64) {
	pack := &msg_proto.SCMessageList{}
	if len(this.msgs) != 0 {
		for _, msg := range this.msgs {

			if msg.State != model.MSGSTATE_REMOVEED && (msg.ShowId == model.HallAll || msg.ShowId&showId != 0) {

				giftState := int32(0)
				//if len(msg.GiftId) > 0 {
				//	gift := GiftMgrSington.GetFromRecvGift(this.SnId, msg.GiftId)
				//	if gift != nil {
				//		giftState = gift.State
				//	} else {
				//		logger.Logger.Error("player: ", this.SnId, " not find gift : ", msg.GiftId)
				//	}
				//}
				pack.Msgs = append(pack.Msgs, &msg_proto.MessageData{
					Id:          proto.String(msg.Id.Hex()),
					Title:       proto.String(msg.Title),
					Content:     proto.String(msg.Content),
					MType:       proto.Int32(msg.MType),
					SrcId:       proto.Int32(msg.SrcId),
					SrcName:     proto.String(msg.SrcName),
					Coin:        proto.Int64(msg.Coin),
					Diamond:     proto.Int64(msg.Diamond),
					Ticket:      proto.Int64(msg.Ticket),
					Grade:       proto.Int64(msg.Grade),
					State:       proto.Int32(msg.State),
					Ts:          proto.Int32(int32(msg.CreatTs)),
					Params:      msg.Params,
					AttachState: proto.Int32(msg.AttachState),
					GiftId:      proto.String(msg.GiftId),
					GiftState:   proto.Int32(giftState),
				})
			}
		}
		proto.SetDefaults(pack)
	}
	//nil的msg需要发给前端便于覆盖前一个玩家的信息
	this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGELIST), pack)
}

func (this *Player) ReadMessage(id string) {
	if msg, exist := this.msgs[id]; exist {
		if msg.State == model.MSGSTATE_UNREAD {
			msg.State = model.MSGSTATE_READED

			task.New(nil,
				task.CallableWrapper(func(o *basic.Object) interface{} {
					return model.ReadMessage(msg.Id, msg.Platform)
				}),
				task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
					if data == nil {
						pack := &msg_proto.SCMessageRead{
							Id: proto.String(id),
						}
						proto.SetDefaults(pack)
						this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEREAD), pack)
					}
				}), "ReadMessage").StartByFixExecutor("logic_message")
		}
	}
}

func (this *Player) WebDelMessage(id string) {
	if msg, exist := this.msgs[id]; exist {
		if msg.State != model.MSGSTATE_REMOVEED { // 未删除状态通知客户端
			pack := &msg_proto.SCMessageDel{
				Id: id,
			}

			proto.SetDefaults(pack)
			this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEDEL), pack)
		}
		//删除此邮件
		delete(this.msgs, id)
	}
}

func (this *Player) DelMessage(id string, del int32) bool {
	if msg, exist := this.msgs[id]; exist {
		if msg.State != model.MSGSTATE_REMOVEED {

			task.New(nil,
				task.CallableWrapper(func(o *basic.Object) interface{} {
					args := &model.DelMsgArgs{
						Platform: msg.Platform,
						Id:       msg.Id,
						Del:      del,
					}
					return model.DelMessage(args)
				}),
				task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
					if data == nil {
						pack := &msg_proto.SCMessageDel{
							Id: id,
						}

						proto.SetDefaults(pack)
						this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEDEL), pack)

						msg.State = model.MSGSTATE_REMOVEED
						//删除此邮件
						delete(this.msgs, id)
					}
				}), "DelMessage").StartByFixExecutor("logic_message")

			return true
		}
	}
	return false
}
func (this *Player) MessageShowRed() {
	msgMap := make(map[int64]int)
	for _, msg := range this.msgs {
		if msg.State == model.MSGSTATE_UNREAD ||
			(msg.State == model.MSGSTATE_READED && msg.AttachState == model.MSGATTACHSTATE_DEFAULT &&
				(msg.Coin > 0 || msg.Diamond > 0 || len(msg.Params) > 0)) {
			if msg.ShowId == model.HallAll {
				msgMap[model.HallMain] = 1
				msgMap[model.HallTienlen] = 1
				msgMap[model.HallFish] = 1
			} else {
				msgMap[msg.ShowId] = 1
			}
		}
	}
	for showId := range msgMap {
		this.SendShowRed(hall_proto.ShowRedCode_Mail, int32(showId), 1)
	}
}

/*
func (this *Player) DelAllMessage() bool {

	var keys []string
	args := &model.DelAllMsgArgs{}
	pack := &msg_proto.SCMessageDel{}
	for key, _ := range this.msgs {
		if msg, exist := this.msgs[key]; exist {
			if msg.State == model.MSGSTATE_REMOVEED {
				break
			}
			msg.State = model.MSGSTATE_REMOVEED
			// model.DelMessage(msg.Id, msg.Platform)
			keys = append(keys, key)
			pack.Ids = append(pack.Ids, msg.Id.Hex())
			args.Ids = append(args.Ids, msg.Id)
		}
	}
	for _, key := range keys {
		delete(this.msgs, key)
	}

	task.New(nil,
		task.CallableWrapper(func(o *basic.Object) interface{} {
			return model.DelAllMessage(args)
		}),
		task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
			if data == nil {
				pack := &msg_proto.SCMessageDel{}
				for _, id := range keys {
					pack.Ids = append(pack.Ids, id)
					delete(this.msgs, id)
				}
				proto.SetDefaults(pack)
				this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEDEL), pack)
				for _, msg := range this.msgs {
					if msg.State == model.MSGSTATE_REMOVEED {
						break
					}
					msg.State = model.MSGSTATE_REMOVEED
				}

				//删除此邮件

			}
		}), "DelMessage").StartByFixExecutor("logic_message")

	proto.SetDefaults(pack)
	this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEDEL), pack)

	return true

}*/

func (this *Player) AddMessage(msg *model.Message) {
	if msg == nil {
		return
	}

	if _, exist := this.msgs[msg.Id.Hex()]; !exist {
		this.msgs[msg.Id.Hex()] = msg

		//giftState := int32(0)
		//if len(msg.GiftId) > 0 {
		//	gift := GiftMgrSington.GetFromRecvGift(this.SnId, msg.GiftId)
		//	if gift != nil {
		//		giftState = gift.State
		//	} else {
		//		logger.Logger.Error("player: ", this.SnId, " not find gift : ", msg.GiftId)
		//	}
		//}

		//pack := &msg_proto.SCMessageAdd{
		//	Msg: &msg_proto.MessageData{
		//		Id:          proto.String(msg.Id.Hex()),
		//		Title:       proto.String(msg.Title),
		//		Content:     proto.String(msg.Content),
		//		MType:       proto.Int32(msg.MType),
		//		SrcId:       proto.Int32(msg.SrcId),
		//		SrcName:     proto.String(msg.SrcName),
		//		Coin:        proto.Int64(msg.Coin),
		//		Ticket:      proto.Int64(msg.Ticket),
		//		Grade:       proto.Int64(msg.Grade),
		//		State:       proto.Int32(msg.State),
		//		Ts:          proto.Int32(int32(msg.CreatTs)),
		//		Params:      msg.Params,
		//		AttachState: proto.Int32(msg.AttachState),
		//		GiftId:      proto.String(msg.GiftId),
		//		GiftState:   proto.Int32(giftState),
		//	},
		//}
		//
		//proto.SetDefaults(pack)
		//this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_MESSAGEADD), pack)

		//if len(this.msgs) > model.MSG_MAX_COUNT {
		//如果邮件达到上限,删除最旧的一封邮件，调整一下，如果有附件没有领取，就不删除
		// OldestKeyId := msg.Id.Hex()
		this.verifyoneMessage(msg) // 最新的一封时间最大

		//}
		msgMap := make(map[int64]int)
		if msg.ShowId == model.HallAll {
			msgMap[model.HallMain] = 1
			msgMap[model.HallTienlen] = 1
			msgMap[model.HallFish] = 1
		} else {
			msgMap[msg.ShowId] = 1
		}
		for showId := range msgMap {
			this.SendShowRed(hall_proto.ShowRedCode_Mail, int32(showId), 1)
		}
	}
}

func (this *Player) verifyoneMessage(msg *model.Message) {
	var len int
	for _, m := range this.msgs {
		if m.ShowId == model.HallAll || m.ShowId&msg.ShowId != 0 {
			len++
		}
	}
	OldestKeyId := msg.Id.Hex()
	OldestCreatTs := msg.CreatTs

	if len > model.MSG_MAX_COUNT {
		for id, m := range this.msgs {
			if m.ShowId == model.HallAll || m.ShowId&msg.ShowId != 0 {
				if m.CreatTs < OldestCreatTs {
					OldestCreatTs = m.CreatTs
					OldestKeyId = id
				}
			}
		}
		this.DelMessage(OldestKeyId, 1)
	}
}

type msgsort struct {
	Id []string
	Ts []int64
}

func (p *msgsort) Len() int           { return len(p.Id) }
func (p *msgsort) Less(i, j int) bool { return p.Ts[i] > p.Ts[j] }
func (p *msgsort) Swap(i, j int) {
	p.Id[i], p.Id[j] = p.Id[j], p.Id[i]
	p.Ts[i], p.Ts[j] = p.Ts[j], p.Ts[i]
}
func (p *msgsort) Sort() { sort.Sort(p) }

// 初始化
func (this *Player) verifyMessage1() {
	var delId []string
	// delmap := make(map[string]bool)
	var mainsort, tiensort, fishsort msgsort

	for id, m := range this.msgs {

		if m.ShowId == model.HallAll { // 所有可见
			mainsort.Id = append(mainsort.Id, id)
			mainsort.Ts = append(mainsort.Ts, m.CreatTs)
			tiensort.Id = append(tiensort.Id, id)
			tiensort.Ts = append(tiensort.Ts, m.CreatTs)
			fishsort.Id = append(fishsort.Id, id)
			fishsort.Ts = append(fishsort.Ts, m.CreatTs)
		} else {
			if m.ShowId&model.HallMain != 0 {
				mainsort.Id = append(mainsort.Id, id)
				mainsort.Ts = append(mainsort.Ts, m.CreatTs)
			} else if m.ShowId&model.HallTienlen != 0 {
				tiensort.Id = append(tiensort.Id, id)
				tiensort.Ts = append(tiensort.Ts, m.CreatTs)
			} else if m.ShowId&model.HallFish != 0 {
				fishsort.Id = append(fishsort.Id, id)
				fishsort.Ts = append(fishsort.Ts, m.CreatTs)
			}
		}

	}

	if mainsort.Len() > model.MSG_MAX_COUNT {
		sort.Sort(&mainsort)
		delId = append(delId, mainsort.Id[model.MSG_MAX_COUNT:]...)
	}
	if tiensort.Len() > model.MSG_MAX_COUNT {
		sort.Sort(&tiensort)
		delId = append(delId, tiensort.Id[model.MSG_MAX_COUNT:]...)
	}
	if fishsort.Len() > model.MSG_MAX_COUNT {
		sort.Sort(&fishsort)
		delId = append(delId, fishsort.Id[model.MSG_MAX_COUNT:]...)
	}

	for _, id := range delId {
		this.DelMessage(id, 1)
	}
}

func (this *Player) verifyMessage(maxCreatTs int64) {
	var OldmainKeyId, OldsunKeyId []string
	var mainnum, sunnum int

	for id, m := range this.msgs {

		if m.CreatTs < maxCreatTs {
			if m.ShowId == model.HallAll || m.ShowId&model.HallMain != 0 {
				mainnum++
			} else {
				sunnum++
			}
			if mainnum > model.MSG_MAX_COUNT { // 主大厅
				OldmainKeyId = append(OldmainKeyId, id)
			} else if sunnum > model.MSG_MAX_COUNT { // 子大厅
				OldsunKeyId = append(OldsunKeyId, id)
			}
			/*if (m.Coin <= 0 && m.Ticket <= 0 && m.Grade <= 0) || m.AttachState == model.MSGATTACHSTATE_GOT {
				OldestCreatTs = m.CreatTs

			}*/
		}
	}

	for _, id := range OldmainKeyId {
		this.DelMessage(id, 1)
	}
	for _, id := range OldsunKeyId {
		this.DelMessage(id, 1)
	}
}

func (this *Player) EditMessage(msg *model.Message) {
	if msg == nil {
		return
	}

	if _, exist := this.msgs[msg.Id.Hex()]; exist {
		this.msgs[msg.Id.Hex()] = msg
	}
}

func (this *Player) SendIosInstallStableMail() {
	if this.layered[common.ActId_IOSINSTALLSTABLE] {
		logger.Logger.Trace("this.layered[common.ActId_IOSINSTALLSTABLE] is true")
		return
	}
	var newMsg *model.Message
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		newMsg = model.NewMessage("", 0, "", this.SnId, model.MSGTYPE_IOSINSTALLSTABLE, "系统通知", fmt.Sprintf("感谢您下载稳定版本，额外奖励%d元，请查收", int(model.GameParamData.IosStableInstallPrize/100)),
			int64(model.GameParamData.IosStableInstallPrize), 0, 0, time.Now().Unix(), 0, "", nil, this.Platform, model.HallAll)
		return model.InsertMessage(this.Platform, newMsg)
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if data == nil {
			this.AddMessage(newMsg)
		}
	}), "SendMessage").Start()
}

func (this *Player) TestMail() {

	var newMsg *model.Message

	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		var otherParams []int32
		otherParams = append(otherParams, 10001, 3)
		otherParams = append(otherParams, 20001, 3)
		otherParams = append(otherParams, 20002, 3)
		newMsg = model.NewMessage("", 0, "", this.SnId, model.MSGTYPE_ITEM, "系统通知道具test", "测试",
			100000, 100, model.MSGSTATE_UNREAD, time.Now().Unix(), 0, "", otherParams, this.Platform, 0)
		return model.InsertMessage(this.Platform, newMsg)
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if data == nil {
			this.AddMessage(newMsg)

		}
	}), "TestSendMessage").Start()
}

func (this *Player) TestSubMail() {

	var newMsg *model.Message

	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		var otherParams []int32
		otherParams = append(otherParams, 10001, 3)
		otherParams = append(otherParams, 20001, 3)
		otherParams = append(otherParams, 20002, 3)
		newMsg = model.NewMessage("", 0, "", 0, model.MSGTYPE_ITEM, "系统", "测试",
			100000, 100, model.MSGSTATE_UNREAD, time.Now().Unix(), 0, "", otherParams, this.Platform, model.HallTienlen)
		return model.InsertMessage(this.Platform, newMsg)
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if data == nil {
			MsgMgrSington.AddMsg(newMsg)
		}
	}), "TestSubSendMessage").Start()
}

func (this *Player) ClubChangeCoin(gainWay int32, coin int64, remark string) {
	this.AddCoin(coin, 0, gainWay, "", remark)
}
func (this *Player) GetMessageAttach(id string) {
	if msg, exist := this.msgs[id]; exist {
		if msg.AttachState == model.MSGATTACHSTATE_DEFAULT && (msg.Coin > 0 || msg.Ticket > 0 ||
			msg.Grade > 0 || len(msg.Params) > 0 || msg.Diamond > 0) {
			task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
				gift, err := model.GetMessageById(msg.Id.Hex(), msg.Platform)
				if err != nil || gift == nil {
					return nil
				}
				if gift.AttachState == model.MSGATTACHSTATE_GOT {
					return nil
				}
				err = model.GetMessageAttach(msg.Id, msg.Platform)
				if err != nil {
					return nil
				}
				return gift
			}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
				attach_msg, ok := data.(*model.Message)
				dirtyCoin := int64(0)
				if ok && attach_msg != nil {
					msg.AttachState = model.MSGATTACHSTATE_GOT
					notifyClient := true
					var remark string
					var gainWay int32 = common.GainWay_MessageAttach

					// 领取道具
					addItem := func() {
						items := make([]*Item, 0)
						if num := len(msg.Params); num > 0 && num%2 == 0 {
							for i := 0; i < num; i += 2 {
								items = append(items, &Item{
									ItemId:     msg.Params[i],          // 物品id
									ItemNum:    int64(msg.Params[i+1]), // 数量
									ObtainTime: time.Now().Unix(),
								})
							}
							if _, code := BagMgrSingleton.AddJybBagInfo(this, items, 0, gainWay, "mail", remark); code != bag.OpResultCode_OPRC_Sucess { // 领取失败
								logger.Logger.Errorf("CSPlayerSettingHandler AddJybBagInfo err", code)
								pack := &msg_proto.SCGetMessageAttach{
									Id: proto.String(""),
								}
								proto.SetDefaults(pack)
								this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_GETMESSAGEATTACH), pack)
							} else {
								var itemIds []int32
								for _, v := range items {
									itemIds = append(itemIds, v.ItemId)
									itemData := srvdata.PBDB_GameItemMgr.GetData(v.ItemId)
									if itemData != nil {
										BagMgrSingleton.RecordItemLog(this.Platform, this.SnId, ItemObtain, v.ItemId, itemData.Name, v.ItemNum, "邮件领取")
									}
								}
								PetMgrSington.CheckShowRed(this)
							}
							this.dirty = true
						}
					}

					switch msg.MType {
					case model.MSGTYPE_ITEM:
						remark = "领取道具"
						gainWay = common.GainWay_MAIL_MTEM
						dirtyCoin = msg.Coin
						addItem()
					case model.MSGTYPE_IOSINSTALLSTABLE:
						remark = "IOS下载稳定版本"
						gainWay = common.GainWay_IOSINSTALLSTABLE
						dirtyCoin = msg.Coin
					case model.MSGTYPE_GIFT:
						remark = "礼物"
					case model.MSGTYPE_GOLDCOMERANK:
						remark = "财神降临奖励"
						gainWay = common.GainWay_GoldCome
						notifyClient = false
						dirtyCoin = msg.Coin
					case model.MSGTYPE_RANDCOIN:
						remark = "红包雨"
						gainWay = common.GainWay_OnlineRandCoin
						notifyClient = false
						dirtyCoin = msg.Coin
					case model.MSGTYPE_REBATE:
						remark = "流水返利"
						gainWay = common.GainWay_RebateTask
						notifyClient = false
						dirtyCoin = msg.Coin
						//邮件领取 添加日志
						task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
							return model.InsertRebateLog(this.Platform, &model.Rebate{
								SnId:        this.SnId,
								RebateCoin:  msg.Coin,
								ReceiveType: 1,
								CodeCoin:    0,
							})
						}), nil, "InsertRebateLog").StartByFixExecutor("ReceiveCodeCoin")
					case model.MSGTYPE_ClubGet:
						//if len(msg.Params) != 0 {
						//	//如果俱乐部解散 就存msg.Params[0]
						//	remark = fmt.Sprintf("%v", msg.Params[0])
						//}
						//gainWay = common.GainWay_ClubGetCoin
						//dirtyCoin = msg.Coin
					case model.MSGTYPE_ClubPump:
						//if len(msg.Params) != 0 {
						//	remark = fmt.Sprintf("%v", msg.Params[0])
						//}
						//gainWay = common.GainWay_ClubPumpCoin
						//notifyClient = false
						//dirtyCoin = msg.Coin
					case model.MSGTYPE_MATCH_SIGNUPFEE:
						gainWay = common.GainWay_MatchBreakBack
						notifyClient = false
					case model.MSGTYPE_MATCH_TICKETREWARD:
						gainWay = common.GainWay_MatchSystemSupply
						notifyClient = false
						this.TicketTotal += msg.Ticket
					case model.MSGTYPE_MATCH_SHOPEXCHANGE:
						remark = "积分商城兑换"
						gainWay = common.GainWay_Exchange
					case model.MSGTYPE_MATCH_SHOPERETURN:
						remark = "撤单返还"
						gainWay = common.GainWay_GradeShopReturn
					case model.MSGTYPE_RANK_REWARD:
						remark = "排位赛段位奖励"
						gainWay = common.GainWay_RankMatch
						addItem()
					}
					if msg.Coin > 0 {
						this.AddCoin(msg.Coin, 0, gainWay, msg.Id.Hex(), remark)
						//增加泥码
						this.AddDirtyCoin(0, dirtyCoin)
						//俱乐部获取不算系统赠送
						if msg.MType != model.MSGTYPE_ClubGet {
							this.ReportSystemGiveEvent(int32(msg.Coin), gainWay, notifyClient) //邮件附件算是系统赠送
						} else { //俱乐部获取算充值
							this.AddCoinGiveLog(msg.Coin, 0, 0, gainWay, model.COINGIVETYPE_PAY, "club", "club")
						}
						this.AddPayCoinLog(msg.Coin, model.PayCoinLogType_Coin, "mail")
						if msg.Oper == 0 { //系统赠送
							LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(this.SnId, this.Name, this.Platform, model.SystemFreeGive_GiveType_MailSystemGive,
								model.SystemFreeGive_CoinType_Coin, int64(msg.Coin)))
						}
					}
					if msg.Ticket > 0 {
						//增加报名券
						this.AddTicket(msg.Ticket, gainWay, msg.Id.Hex(), remark)
					}
					if msg.Grade > 0 {
						//增加积分
						this.AddGrade(msg.Grade, gainWay, msg.Id.Hex(), remark)
					}
					if msg.Diamond > 0 {
						this.AddDiamond(msg.Diamond, 0, gainWay, msg.Id.Hex(), remark)
						if msg.Oper == 0 { //系统赠送
							LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(this.SnId, this.Name, this.Platform, model.SystemFreeGive_GiveType_MailSystemGive,
								model.SystemFreeGive_CoinType_Diamond, int64(msg.Diamond)))
						}
					}
					pack := &msg_proto.SCGetMessageAttach{
						Id: proto.String(id),
					}
					proto.SetDefaults(pack)
					this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_GETMESSAGEATTACH), pack)
				}
			}), "GetMessageAttach").StartByFixExecutor("logic_message")
		}
	}
}

// 一键领取
func (this *Player) GetMessageAttachs(ids []string) {
	var msgs []*model.Message
	var Ids []string // 可以领取的邮件
	var platform string
	for _, id := range ids {
		if msg, exist := this.msgs[id]; exist {
			if msg.AttachState == model.MSGATTACHSTATE_DEFAULT && (msg.Coin > 0 || msg.Ticket > 0 ||
				msg.Grade > 0 || len(msg.Params) > 0 || msg.Diamond > 0) {
				Ids = append(Ids, id)
				platform = msg.Platform
			}
		}
	}

	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {

		magids, err := model.GetMessageAttachs(Ids, platform)
		if err != nil {
			logger.Logger.Trace("GetMessageAttachs err ", err)
		}
		return magids
	}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
		magids, ok := data.(*[]string)

		if ok && magids != nil {
			for _, id := range *magids {
				if msg, exist := this.msgs[id]; exist {
					if msg.AttachState == model.MSGATTACHSTATE_DEFAULT && (msg.Coin > 0 || msg.Ticket > 0 ||
						msg.Grade > 0 || len(msg.Params) > 0 || msg.Diamond > 0) {
						msgs = append(msgs, msg)
						platform = msg.Platform
					}
				}
			}

			pack := &msg_proto.SCGetMessageAttach{
				// Id: proto.String(id),
			}

			for _, msg := range msgs {
				pack.Ids = append(pack.Ids, msg.Id.Hex())
				dirtyCoin := int64(0)
				msg.AttachState = model.MSGATTACHSTATE_GOT
				notifyClient := true
				var remark string
				var gainWay int32 = common.GainWay_MessageAttach
				switch msg.MType {
				case model.MSGTYPE_ITEM:
					remark = "领取道具"
					gainWay = common.GainWay_MAIL_MTEM
					dirtyCoin = msg.Coin
					items := make([]*Item, 0)
					if num := len(msg.Params); num > 0 && num%2 == 0 {
						for i := 0; i < num; i += 2 {
							items = append(items, &Item{
								ItemId:     msg.Params[i],          // 物品id
								ItemNum:    int64(msg.Params[i+1]), // 数量
								ObtainTime: time.Now().Unix(),
							})
						}
						if _, code := BagMgrSingleton.AddJybBagInfo(this, items, 0, gainWay, "mail", remark); code != bag.OpResultCode_OPRC_Sucess { // 领取失败
							logger.Logger.Errorf("CSPlayerSettingHandler AddJybBagInfo err", code)
							/*
								pack := &msg_proto.SCGetMessageAttach{
									Id: proto.String(""),
								}
								proto.SetDefaults(pack)
								this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_GETMESSAGEATTACH), pack)
							*/
						} else {
							var itemIds []int32
							for _, v := range items {
								itemIds = append(itemIds, v.ItemId)
								itemData := srvdata.PBDB_GameItemMgr.GetData(v.ItemId)
								if itemData != nil {
									BagMgrSingleton.RecordItemLog(this.Platform, this.SnId, ItemObtain, v.ItemId, itemData.Name, v.ItemNum, "邮件领取")
								}
							}
							PetMgrSington.CheckShowRed(this)
						}
						this.dirty = true
					}
				case model.MSGTYPE_IOSINSTALLSTABLE:
					remark = "IOS下载稳定版本"
					gainWay = common.GainWay_IOSINSTALLSTABLE
					dirtyCoin = msg.Coin
				case model.MSGTYPE_GIFT:
					remark = "礼物"
				case model.MSGTYPE_GOLDCOMERANK:
					remark = "财神降临奖励"
					gainWay = common.GainWay_GoldCome
					notifyClient = false
					dirtyCoin = msg.Coin
				case model.MSGTYPE_RANDCOIN:
					remark = "红包雨"
					gainWay = common.GainWay_OnlineRandCoin
					notifyClient = false
					dirtyCoin = msg.Coin
				case model.MSGTYPE_REBATE:
					remark = "流水返利"
					gainWay = common.GainWay_RebateTask
					notifyClient = false
					dirtyCoin = msg.Coin
					//邮件领取 添加日志
					task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
						return model.InsertRebateLog(this.Platform, &model.Rebate{
							SnId:        this.SnId,
							RebateCoin:  msg.Coin,
							ReceiveType: 1,
							CodeCoin:    0,
						})
					}), nil, "InsertRebateLog").StartByFixExecutor("ReceiveCodeCoin")
				case model.MSGTYPE_ClubGet:
					//if len(msg.Params) != 0 {
					//	//如果俱乐部解散 就存msg.Params[0]
					//	remark = fmt.Sprintf("%v", msg.Params[0])
					//}
					//gainWay = common.GainWay_ClubGetCoin
					//dirtyCoin = msg.Coin
				case model.MSGTYPE_ClubPump:
					//if len(msg.Params) != 0 {
					//	remark = fmt.Sprintf("%v", msg.Params[0])
					//}
					//gainWay = common.GainWay_ClubPumpCoin
					//notifyClient = false
					//dirtyCoin = msg.Coin
				case model.MSGTYPE_MATCH_SIGNUPFEE:
					gainWay = common.GainWay_MatchBreakBack
					notifyClient = false
				case model.MSGTYPE_MATCH_TICKETREWARD:
					gainWay = common.GainWay_MatchSystemSupply
					notifyClient = false
					this.TicketTotal += msg.Ticket
				case model.MSGTYPE_MATCH_SHOPEXCHANGE:
					remark = "积分商城兑换"
					gainWay = common.GainWay_Exchange
				case model.MSGTYPE_MATCH_SHOPERETURN:
					remark = "撤单返还"
					gainWay = common.GainWay_GradeShopReturn
				}
				if msg.Coin > 0 {
					this.AddCoin(msg.Coin, 0, gainWay, msg.Id.Hex(), remark)
					//增加泥码
					this.AddDirtyCoin(0, dirtyCoin)
					//俱乐部获取不算系统赠送
					if msg.MType != model.MSGTYPE_ClubGet {
						this.ReportSystemGiveEvent(int32(msg.Coin), gainWay, notifyClient) //邮件附件算是系统赠送
					} else { //俱乐部获取算充值
						this.AddCoinGiveLog(msg.Coin, 0, 0, gainWay, model.COINGIVETYPE_PAY, "club", "club")
					}
					this.AddPayCoinLog(msg.Coin, model.PayCoinLogType_Coin, "mail")
					if msg.Oper == 0 { //系统赠送
						LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(this.SnId, this.Name, this.Platform, model.SystemFreeGive_GiveType_MailSystemGive,
							model.SystemFreeGive_CoinType_Coin, int64(msg.Coin)))
					}
				}
				if msg.Ticket > 0 {
					//增加报名券
					this.AddTicket(msg.Ticket, gainWay, msg.Id.Hex(), remark)
				}
				if msg.Grade > 0 {
					//增加积分
					this.AddGrade(msg.Grade, gainWay, msg.Id.Hex(), remark)
				}
				if msg.Diamond > 0 {
					this.AddDiamond(msg.Diamond, 0, gainWay, msg.Id.Hex(), remark)
					if msg.Oper == 0 { //系统赠送
						LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(this.SnId, this.Name, this.Platform, model.SystemFreeGive_GiveType_MailSystemGive,
							model.SystemFreeGive_CoinType_Diamond, int64(msg.Diamond)))
					}
				}

			}

			proto.SetDefaults(pack)
			this.SendToClient(int(msg_proto.MSGPacketID_PACKET_SC_GETMESSAGEATTACH), pack)
		}
	}), "GetMessageAttach").StartByFixExecutor("logic_message")

}

func (this *Player) GetMessageByGiftId(id string) *model.Message {
	for _, msg := range this.msgs {
		if msg.GiftId == id && msg.State != model.MSGSTATE_REMOVEED {
			return msg
		}
	}
	return nil
}

// 踢掉线
func (this *Player) Kickout(reason int32) {
	if this.IsOnLine() {
		logger.Logger.Trace("(this *Player) Kickout()", this.SnId)
		scDisconnect := &login_proto.SSDisconnect{
			SessionId: proto.Int64(this.sid),
			Type:      proto.Int32(reason),
		}
		proto.SetDefaults(scDisconnect)
		this.SendToClient(int(login_proto.GatePacketID_PACKET_SS_DICONNECT), scDisconnect)

		LoginStateMgrSington.LogoutBySid(this.sid)
		this.DropLine()
		this.DgGameLogout()
	}
}

// DropLine 掉线
// 1.玩家登出
// 2.玩家网络断开
// 3.被踢掉线
func (this *Player) DropLine() {
	logger.Logger.Tracef("(this *Player) DropLine() %v", this.SnId)
	if !this.IsRob {
		TournamentMgr.Quit(this.Platform, this.SnId)

		// 记录掉线日志
		logState := LoginStateMgrSington.GetLoginStateBySid(this.sid)
		var clog *model.ClientLoginInfo
		if logState != nil {
			clog = logState.clog
		}
		var gameid int
		if this.scene != nil && this.scene.gameSess != nil {
			gameid = this.scene.gameId
		}
		LogChannelSingleton.WriteLog(model.NewLoginLog(this.SnId, common.LoginLogTypeDrop, this.Tel, this.Ip,
			this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.City, clog, this.GetTotalCoin(),
			gameid, this.LastGameId, this.DeviceName, this.PackageName, this.AppVersion, this.BuildVersion, this.AppChannel))

		this.SendPlayerCoin()
		this.OnlineLogDrop()

		PlayerOnlineSington.Check = true
	}

	this.SetOffline()
	this.PlayerData.LastLogoutTime = time.Now().Local()
	FriendMgrSington.UpdateLogoutTime(this.Platform, this.SnId)
	if this.scene != nil && this.scene.gameSess != nil {
		pack := &server_proto.WGPlayerDropLine{
			Id:      proto.Int32(this.SnId),
			SceneId: proto.Int(this.scene.sceneId),
		}
		proto.SetDefaults(pack)
		this.SendToGame(int(server_proto.SSPacketID_PACKET_WG_PLAYERDROPLINE), pack)
	}
	PlayerMgrSington.DroplinePlayer(this)
	PlatformMgrSingleton.PlayerLogout(this)
	this.sid = 0
	this.gateSess = nil
	//统计在线时长日志
	//this.StatisticsOllen(this.PlayerData.LastLogoutTime)

	gameStateMgr.PlayerClear(this)

	//玩家掉线事件
	FirePlayerDropLine(this)
}

// 退出
func (this *Player) Logout() {
	logger.Logger.Tracef("(this *Player) Logout() %v", this.SnId)
	//退出比赛
	//this.QuitMatch(false)
	// 在线奖励：累计在线时长
	//this.OnlineRewardAddUpOnlineDuration()

	scLogout := &login_proto.SCLogout{
		OpRetCode: login_proto.OpResultCode_OPRC_Sucess,
	}
	proto.SetDefaults(scLogout)
	this.SendToClient(int(login_proto.LoginPacketID_PACKET_SC_LOGOUT), scLogout)
	this.SetOffline()
	this.LastLogoutTime = time.Now().Local()
	FriendMgrSington.UpdateLogoutTime(this.Platform, this.SnId)
	//clubManager.DropLinePlayer(this.SnId)
	PlayerMgrSington.DroplinePlayer(this)
	PlatformMgrSingleton.PlayerLogout(this)
	if !this.IsRobot() {
		PlayerOnlineSington.Check = true
	}
	this.sid = 0
	this.gateSess = nil
	this.DgGameLogout()
	gameStateMgr.PlayerClear(this)
	this.OnlineLogLogout()
}

func (this *Player) DgGameLogout() {
	//if this.scene != nil {
	//	if this.scene.sceneId == SceneMgrSingleton.GetDgSceneId() {
	//		var agentName, agentKey, thirdPlf string
	//		if len(this.BakDgHboName) > 0 {
	//			if strings.Contains(this.BakDgHboName, "dg") {
	//				agentName, agentKey, thirdPlf = model.OnlyGetDgConfigByPlatform(this.Platform)
	//			} else {
	//				agentName, agentKey, thirdPlf = model.OnlyGetHboConfigByPlatform(this.Platform)
	//			}
	//
	//			task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
	//				webapi.API_DgLogout(thirdPlf, common.GetAppId(), this.DgGame, this.DgPass, agentName, agentKey)
	//				return nil
	//			}), task.CompleteNotifyWrapper(func(data interface{}, t *task.Task) {
	//				this.scene = nil
	//			}), "DgGameLogout").Start()
	//		}
	//
	//	}
	//}
}

func (this *Player) ThirdGameLogout() {
	_LeaveTransferThird2SystemTask(this)
}

func (this *Player) IsOnLine() bool {
	return this.state != PlayerStateOffline
}

func (this *Player) SetOnline() {
	this.state = PlayerStateOnline
}

func (this *Player) IsOffline() bool {
	return this.state == PlayerStateOffline
}

func (this *Player) SetOffline() {
	this.state = PlayerStateOffline
}

// OnLogouted 玩家登出
func (this *Player) OnLogouted() {
	logger.Logger.Tracef("(this *Player) OnLogouted() %v", this.SnId)

	//在线时长日志
	//this.WriteOllenLog()

	if !this.IsRob {
		FriendUnreadMgrSington.SaveFriendUnreadData(this.Platform, this.SnId)
		MatchSeasonMgrSington.SaveMatchSeasonData(this.SnId, true)
	}
	//平台数据
	PlatformMgrSingleton.PlayerLogout(this)
	//PlayerSingleAdjustMgr.DelPlayerData(this.Platform, this.SnId)

	//离线玩家清空俱乐部信息
	//delete(clubManager.theInClubId, this.SnId)

	//玩家登出事件
	FirePlayerLogouted(this)

	//登录日志
	logState := LoginStateMgrSington.GetLoginStateBySid(this.sid)
	var clog *model.ClientLoginInfo
	if logState != nil {
		clog = logState.clog
	}
	//排除掉机器人
	if !this.IsRob {
		LogChannelSingleton.WriteLog(model.NewLoginLog(this.SnId, common.LoginLogTypeLogout, this.Tel, this.Ip,
			this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.City, clog, this.GetTotalCoin(),
			0, 0, this.DeviceName, this.PackageName, this.AppVersion, this.BuildVersion, this.AppChannel))
		this.OnlineLogLogout()
	}

	//退出通知
	//ActMonitorMgrSington.SendActMonitorEvent(ActState_Login, this.SnId, this.Name, this.Platform, 0, 0, "", 1)

	// 更新数据库
	logger.Logger.Tracef("###%v unmount from DBSaver[DelPlayer]", this.Name)
	DbSaver_Inst.UnregisteDbSaveTask(this)
	this.Save(true)
}

func (this *Player) MarshalData(gameid int) (d []byte, e error) {
	d, e = netlib.Gob.Marshal(this.PlayerData)
	return
}

func (this *Player) MarshalSingleAdjustData(gamefreeid int32) (d []byte, e error) {
	if this.IsRob {
		return
	}
	sa := PlayerSingleAdjustMgr.GetSingleAdjust(this.Platform, this.SnId, gamefreeid)
	if sa != nil {
		d, e = netlib.Gob.Marshal(sa)
	}
	return
}

// UnmarshalData 更新玩家数据
// 例如游戏服数据同步
func (this *Player) UnmarshalData(data []byte, scene *Scene) {
	pd := &model.PlayerData{}
	if err := netlib.Gob.Unmarshal(data, pd); err != nil {
		logger.Logger.Warn("Player.SyncData err:", err)
		return
	}

	// GDatas 同步
	for _, v := range []string{
		strconv.Itoa(int(scene.dbGameFree.GetId())),
		strconv.Itoa(int(scene.dbGameFree.GetGameId())),
		common.GetKeyNoviceGameId(int(scene.dbGameFree.GetGameId())),
		common.GetKeyGameType(int(scene.dbGameFree.GetGameType())),
	} {
		if d, ok := pd.GDatas[v]; ok {
			this.GDatas[v] = d
		}
	}

	this.LastRechargeWinCoin = pd.LastRechargeWinCoin
	oldRecharge := int64(0)
	oldExchange := int64(0)
	if this.PlayerData.TodayGameData != nil {
		oldRecharge = this.PlayerData.TodayGameData.RechargeCoin
		oldExchange = this.PlayerData.TodayGameData.ExchangeCoin
	}
	this.PlayerData.TodayGameData = pd.TodayGameData
	if this.PlayerData.TodayGameData != nil {
		this.PlayerData.TodayGameData.RechargeCoin = oldRecharge
		this.PlayerData.TodayGameData.ExchangeCoin = oldExchange
	}
	this.PlayerData.YesterdayGameData = pd.YesterdayGameData
	this.PlayerData.IsFoolPlayer = pd.IsFoolPlayer
	this.PlayerData.TotalGameData = pd.TotalGameData
	this.PlayerData.WinTimes = pd.WinTimes
	this.PlayerData.FailTimes = pd.FailTimes
	this.PlayerData.DrawTimes = pd.DrawTimes
	this.PlayerData.WinCoin = pd.WinCoin
	this.PlayerData.FailCoin = pd.FailCoin
	this.PlayerData.TotalIn = pd.TotalIn
	this.PlayerData.TotalOut = pd.TotalOut
	this.PlayerData.ChessGrade = pd.ChessGrade
	this.PlayerData.MoneyPond = pd.MoneyPond
	this.PlayerData.FishLevel = pd.FishLevel
	this.PlayerData.FishExp = pd.FishExp
	this.PlayerData.UnMaxPower = pd.UnMaxPower
	this.PlayerData.PowerList = pd.PowerList
	this.PlayerData.PlayerTax = pd.PlayerTax
	this.PlayerData.TotalFlow = pd.TotalFlow
	this.dirty = true
}

func (this *Player) MarshalIParam() []*server_proto.PlayerIParam {
	var params []*server_proto.PlayerIParam
	for i, v := range this.Iparams {
		params = append(params, &server_proto.PlayerIParam{
			ParamId: proto.Int(i),
			IntVal:  proto.Int64(v),
		})
	}
	return params
}

func (this *Player) UnmarshalIParam(params []*server_proto.PlayerIParam) {
	for _, p := range params {
		this.Iparams[int(p.GetParamId())] = p.GetIntVal()
	}
}

func (this *Player) MarshalSParam() []*server_proto.PlayerSParam {
	var params []*server_proto.PlayerSParam
	for i, v := range this.sparams {
		params = append(params, &server_proto.PlayerSParam{
			ParamId: proto.Int(i),
			StrVal:  proto.String(v),
		})
	}
	return params
}

func (this *Player) UnmarshalSParam(params []*server_proto.PlayerSParam) {
	for _, p := range params {
		this.sparams[int(p.GetParamId())] = p.GetStrVal()
	}
}

func (this *Player) MarshalCParam() []*server_proto.PlayerCParam {
	var params []*server_proto.PlayerCParam
	for k, v := range this.cparams {
		params = append(params, &server_proto.PlayerCParam{
			StrKey: proto.String(k),
			StrVal: proto.String(v),
		})
	}
	return params
}

func (this *Player) SendToRepSrv(pd *model.PlayerData) {
	//replaySess := srvlib.ServerSessionMgrSington.GetSession(common.GetSelfAreaId(), ReplayServerType, ReplayServerId)
	//if replaySess != nil {
	//	var buf bytes.Buffer
	//	enc := gob.NewEncoder(&buf)
	//	err := enc.Encode(pd)
	//	if err != nil {
	//		logger.Logger.Info("(this *Player) SendToRepSrv json.Marshal error", err)
	//	} else {
	//		pack := &server_proto.WRPlayerData{
	//			PlayerData: buf.Bytes(),
	//		}
	//		proto.SetDefaults(pack)
	//		replaySess.Send(int(server_proto.SSPacketID_PACKET_WR_PlayerData), pack)
	//	}
	//}
}

func (this *Player) CanDelete() bool {
	if this.isDelete {
		return true
	}
	return !this.IsOnLine() &&
		!this.dirty &&
		time.Now().Sub(this.lastSaved) > time.Minute*5 &&
		this.scene == nil
}

func (this *Player) Time2Save() {
	this.Save(false)
	if this != nil && this.CanDelete() {
		PlayerMgrSington.DelPlayer(this.SnId)
	}
}

func (this *Player) Save(force bool) {
	if this.isDelete {
		return
	}
	// 用户缓存数据清除前同步到player_logicleveldata
	if !this.IsRob {
		pi := model.ClonePlayerData(this.PlayerData)
		if pi != nil {
			this.SendToRepSrv(pi)
		}
		this.SendPlayerCoin()
	}

	if !this.dirty && !force {
		return
	}

	this.dirty = false
	if !this.IsRob { //机器人数据不再保存
		logger.Logger.Infof("(this *Player) Time2Save() %v", this.SnId)
		pi := model.ClonePlayerData(this.PlayerData)
		if pi != nil {
			this.SendToRepSrv(pi)
			// 跨天任务依赖LastLogoutTime的准确性，跨天任务是定时器ClockMgrSington触发的，所以这里要用定时器的触发时间
			pi.LastLogoutTime = ClockMgrSington.LastTickTime
			t := task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
				if !model.SavePlayerData(pi) {
					//save 失败先写到json里面
					model.BackupPlayerData(pi)
					return false
				}
				for _, v := range internal.GetPlayerLoads() {
					v.Save(pi.Platform, pi.SnId, true, force)
				}
				return true
			}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
				if saved, ok := i.(bool); ok && saved {
					bak := fmt.Sprintf("%v.json", pi.AccountId)
					if exist, _ := common.PathExists(bak); exist {
						os.Remove(bak)
					}
				}
			}), "SavePlayerTask")
			if b := t.StartByExecutor(strconv.Itoa(int(this.SnId))); b {
				this.lastSaved = time.Now()
			}
		}
	}
}

func (this *Player) GetCoin() int64 {
	return this.Coin
}

//func (this *Player) TotalData(num int64, gainWay int32) {
//	if this.IsRob {
//		return
//	}
//	//num = int64(math.Abs(float64(num)))
//	//sort := common.GetSortByGainWay(gainWay)
//	//switch sort {
//	//case common.GainWaySort_Act:
//	//	//活动金额累加
//	//	this.ActivityCoin += int32(num)
//	//case common.GainWaySort_Club:
//	//	switch gainWay {
//	//	case common.GainWay_ClubGiveCoin: //出账
//	//		//俱乐部出账
//	//		this.ClubOutCoin += num
//	//	case common.GainWay_ClubGetCoin:
//	//		//俱乐部入账
//	//		this.ClubInCoin += num
//	//	}
//	//case common.GainWaySort_Rebate:
//	//	//返利获取 也叫 手动洗码
//	//	this.TotalRebateCoin += num
//	//}
//}

// AddDiamond 添加钻石
// num 总数
// add num总数中有多少是加成获得
func (this *Player) AddDiamond(num, add int64, gainWay int32, oper, remark string) {
	if num == 0 {
		return
	}
	logger.Logger.Tracef("snid(%v)  AddDiamond(%v)", this.SnId, num)
	//async := false
	//if num > 0 && this.scene != nil && !this.scene.IsTestScene() && this.scene.sceneMode != common.SceneMode_Thr { //游戏场中加币,需要同步到gamesrv上
	//	if StartAsyncAddCoinTransact(this, num, gainWay, oper, remark, true, 0, true) {
	//		async = true
	//	}
	//}

	if num != 0 /*&& !async*/ {
		this.dirty = true
		if num > 0 {
			this.Diamond += num
		} else {
			if -num > this.Diamond {
				logger.Logger.Errorf("Player.AddCoin exception!!! num(%v) oper(%v)", num, oper)
				num = -this.Diamond
				this.Diamond = 0
			} else {
				this.Diamond += num
			}
		}

		this.SendDiffData()
		if !this.IsRob {
			log := model.NewCoinLogEx(&model.CoinLogParam{
				Platform:   this.Platform,
				SnID:       this.SnId,
				ChangeType: common.BillTypeDiamond,
				ChangeNum:  num,
				RemainNum:  this.Diamond,
				Add:        add,
				LogType:    gainWay,
				GameID:     0,
				GameFreeID: 0,
				BaseCoin:   0,
				Operator:   oper,
				Remark:     remark,
			})
			if log != nil {
				LogChannelSingleton.WriteLog(log)
			}
		}
	}
}

// AddCoin 添加钻石
// num 总数
// add num总数中有多少是加成获得
func (this *Player) AddCoin(num, add int64, gainWay int32, oper, remark string) {
	if num == 0 {
		return
	}
	logger.Logger.Tracef("snid(%v)  AddCoin(%v)", this.SnId, num)

	//this.TotalData(num, gainWay)

	async := false
	if num > 0 && this.scene != nil && !this.scene.IsTestScene() && this.scene.sceneMode != common.SceneMode_Thr { //游戏场中加币,需要同步到gamesrv上
		if StartAsyncAddCoinTransact(this, num, gainWay, oper, remark, true, 0, true) {
			async = true
		}
	}

	if num != 0 && !async {
		this.dirty = true
		if num > 0 {
			this.Coin += num
		} else {
			if -num > this.Coin {
				logger.Logger.Errorf("Player.AddCoin exception!!! num(%v) oper(%v)", num, oper)
				num = -this.Coin
				this.Coin = 0
			} else {
				this.Coin += num
			}
		}

		this.SendDiffData()
		if !this.IsRob {
			log := model.NewCoinLogEx(&model.CoinLogParam{
				Platform:   this.Platform,
				SnID:       this.SnId,
				ChangeType: common.BillTypeCoin,
				ChangeNum:  num,
				RemainNum:  this.Coin,
				Add:        add,
				LogType:    gainWay,
				GameID:     0,
				GameFreeID: 0,
				BaseCoin:   0,
				Operator:   oper,
				Remark:     remark,
			})
			if log != nil {
				LogChannelSingleton.WriteLog(log)
			}
		}
	}
}

func (this *Player) AddCoinAsync(num, add int64, gainWay int32, oper, remark string, broadcast bool, retryCnt int, writeLog bool) bool {
	if num == 0 {
		return false
	}

	//if retryCnt == 0 {
	//	this.TotalData(num, gainWay)
	//}

	//玩家可能正在换房间
	async := false
	if num > 0 && retryCnt < 3 && this.scene != nil && !this.scene.IsTestScene() && this.scene.sceneMode != common.SceneMode_Thr { //游戏场中加币,需要同步到gamesrv上
		if StartAsyncAddCoinTransact(this, num, gainWay, oper, remark, broadcast, retryCnt, writeLog) {
			async = true
		}
	}

	if num != 0 && !async {
		this.dirty = true
		if num > 0 {
			this.Coin += num
		} else {
			if -num > this.Coin {
				logger.Logger.Errorf("Player.AddCoin exception!!! num(%v) oper(%v)", num, oper)
				num = -this.Coin
				this.Coin = 0
			} else {
				this.Coin += num
			}
		}

		this.SendDiffData()
		if !this.IsRob && writeLog {
			log := model.NewCoinLogEx(&model.CoinLogParam{
				Platform:   this.Platform,
				SnID:       this.SnId,
				ChangeType: common.BillTypeCoin,
				ChangeNum:  num,
				RemainNum:  this.Coin,
				Add:        add,
				LogType:    gainWay,
				GameID:     0,
				GameFreeID: 0,
				BaseCoin:   0,
				Operator:   oper,
				Remark:     remark,
			})
			if log != nil {
				LogChannelSingleton.WriteLog(log)
			}
		}
	}

	return async
}

//func (this *Player) AddClubCoin(num int64, gainWay int32, oper, remark string) {
//	if num == 0 {
//		return
//	}
//	this.TotalData(num, gainWay)
//	this.ClubCoin += num
//
//	if num != 0 {
//		this.dirty = true
//		this.SendDiffData()
//		restCnt := this.ClubCoin
//		log := model.NewCoinLogEx(this.SnId, num, restCnt, this.SafeBoxCoin, this.Ver, gainWay, 0,
//			oper, remark, this.Platform, this.Channel, this.BeUnderAgentCode, 0, this.PackageID, 0)
//		if log != nil {
//			CoinLogChannelSington.Write(log)
//		}
//	}
//}

// 增加泥码
func (this *Player) AddDirtyCoin(paycoin, givecoin int64) {
	if this.IsRob {
		return
	}

	//if cfg, ok := ProfitControlMgrSington.GetCfg(this.Platform); ok && cfg != nil && paycoin >= 0 {
	//	//洗码折算率=(玩家剩余泥码*洗码折算率+期望营收)/(充值额+赠送额+泥码余额)
	//	this.RecalcuWashingCoinConvRate(cfg.Rate, paycoin, givecoin)
	//}
	//
	//this.DirtyCoin += paycoin + givecoin
	//if this.DirtyCoin < 0 {
	//	this.DirtyCoin = 0
	//}
	this.dirty = true
}

// 洗码
func (this *Player) WashingCoin(coin int64) int64 {
	if this.IsRob {
		return 0
	}
	if coin <= 0 {
		return 0
	}

	//if this.DirtyCoin > coin {
	//	this.DirtyCoin -= coin
	//	this.dirty = true
	//	return coin
	//}
	//
	////剩余多少泥码，清洗多少
	//coin = this.DirtyCoin
	//this.DirtyCoin = 0
	return coin
}

func (this *Player) AddTicket(num int64, gainWay int32, oper, remark string) {
	if num == 0 {
		return
	}
	if num > 0 {
		this.Ticket += num
	} else {
		if -num > this.Ticket {
			logger.Logger.Errorf("Player.AddTicket exception!!! num(%v) oper(%v)", num, oper)
			num = -this.Ticket
			this.Ticket = 0
		} else {
			this.Ticket += num
		}
	}
	if num != 0 {
		this.dirty = true
		this.diffData.Ticket = -1
		this.SendDiffData()
		//restCnt := this.Ticket
		//log := model.NewTicketLogEx(this.SnId, num, restCnt, this.Ver, gainWay, oper, remark, this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.InviterId)
		//if log != nil {
		//	TicketLogChannelSington.Write(log)
		//}
	}
}

func (this *Player) AddGrade(num int64, gainWay int32, oper, remark string) {
	if num == 0 {
		return
	}
	if num > 0 {
		this.Grade += num
	} else {
		if -num > this.Grade {
			logger.Logger.Errorf("Player.AddGrade exception!!! num(%v) oper(%v)", num, oper)
			num = -this.Grade
			this.Grade = 0
		} else {
			this.Grade += num
		}
	}
	if num != 0 {
		this.dirty = true
		this.diffData.Grade = -1
		this.SendDiffData()
		//restCnt := this.Grade
		//log := model.NewGradeLogEx(this.SnId, num, restCnt, this.Ver, gainWay, oper, remark, this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.InviterId)
		//if log != nil {
		//	GradeLogChannelSington.Write(log)
		//}
	}
}

func (this *Player) AddChessScore(num int64) {
	if num == 0 {
		return
	}
	if num > 0 {
		this.ChessGrade += num
	} else {
		if -num > this.ChessGrade {
			logger.Logger.Errorf("Player.AddChessGrade exception!!! num(%v) oper(%v)", num)
			num = -this.ChessGrade
			this.ChessGrade = 0
		} else {
			this.ChessGrade += num
		}
	}
	if num != 0 {
		this.dirty = true
		this.diffData.ChessGrade = -1
		this.SendDiffData()
		//restCnt := this.Grade
		//log := model.NewGradeLogEx(this.SnId, num, restCnt, this.Ver, gainWay, oper, remark, this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, this.InviterId)
		//if log != nil {
		//	GradeLogChannelSington.Write(log)
		//}
	}
}

func (this *Player) OnSecTimer() {
	FirePlayerSecTimer(this)
}

func (this *Player) OnMiniTimer() {
	FirePlayerMiniTimer(this)
}

func (this *Player) OnHourTimer() {
	FirePlayerHourTimer(this)
}

func (this *Player) OnDayTimer(login, continuous bool, t int) {
	// 校验，跨天操作一天之内只执行一次
	if common.InSameDayNoZero(time.Now().Local(), this.lastOnDayChange) {
		return
	}
	this.lastOnDayChange = time.Now().Local()
	logger.Logger.Infof("(this *Player) (%v) OnDayTimer(%v,%v) ", this.SnId, login, continuous)
	FirePlayerDayTimer(this, login, continuous)

	this.dirty = true
	if login || this.scene == nil {
		//跨天登录 数据给昨天，今天置为空
		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
			}
		*/
	}

	this.OnTimeDayTotal(continuous, t)

	//商城数据更新
	this.ShopTotal = make(map[int32]*model.ShopTotal)
	this.ShopLastLookTime = make(map[int32]int64)
	// 福利活动更新
	WelfareMgrSington.OnDayChanged(this)
	//七日活动
	ActSignMgrSington.OnDayChanged(this)
	this.VipMatchTimes = 0
	//VIP商城数据更新
	this.UpdateVipShopData()
	// 重置每日任务
	if this.WelfData != nil {
		if this.WelfData.Task != nil {
			for _, v := range srvdata.PBDB_TaskMgr.Datas.GetArr() {
				if v.GetActivityType() == common.TaskActivityTypeEveryDay {
					this.WelfData.Task[v.GetId()] = &model.TaskData{}
				}
			}
			this.WelfData.Task[common.TaskIDInvitePlayGame] = &model.TaskData{}
			this.WelfData.Task[common.TaskIDInviteFirstLogin] = &model.TaskData{}
		}
	}
	TaskSubjectSingleton.Touch(common.TaskTypeFirstLogin, &TaskData{SnId: this.SnId, Num: 1}) // 首次登录游戏
	TaskSubjectSingleton.Touch(common.TaskTypeLogin, &TaskData{SnId: this.SnId, Num: 1})      // 登录游戏
}

func (this *Player) OnTimeDayTotal(continuous bool, t int) {
	for k, tgd := range this.TotalGameData {
		for i := 0; i < t; i++ {
			tgd = append(tgd, new(model.PlayerGameTotal))
		}
		if len(tgd) > 30 {
			tgd = tgd[len(tgd)-30:]
		}
		this.TotalGameData[k] = tgd
	}
}

func (this *Player) OnMonthTimer() {
	//判断是否一天即可过滤0点多次切换
	if common.InSameDayNoZero(time.Now().Local(), this.lastOnMonthChange) {
		return
	}
	this.lastOnMonthChange = time.Now().Local()
	FirePlayerMonthTimer(this)
}

func (this *Player) OnWeekTimer() {
	//判断是否一天即可过滤0点多次切换
	if common.InSameDayNoZero(time.Now().Local(), this.lastOnWeekChange) {
		return
	}
	this.lastOnWeekChange = time.Now().Local()
	FirePlayerWeekTimer(this)

	//清理比赛券
	ticket := this.Ticket
	if ticket > 0 {
		this.AddTicket(-ticket, common.GainWay_Expire, "system", "过期清理")
		this.TicketTotalDel += ticket
		this.dirty = true
	}

	if len(this.msgs) > 0 {
		//自然过渡执行
		//过期邮件处理
		var keysId []string
		for key, msg := range this.msgs {
			if msg.AttachState == model.MSGATTACHSTATE_DEFAULT && msg.Ticket > 0 {
				this.TicketTotalDel += msg.Ticket
				keysId = append(keysId, key)
			}
		}
		this.dirty = true
		for _, v := range keysId {
			this.DelMessage(v, 1)
		}
	}

	// 重置周任务
	if this.WelfData != nil {
		if this.WelfData.Task != nil {
			for _, v := range srvdata.PBDB_TaskMgr.Datas.GetArr() {
				if v.GetActivityType() == common.TaskActivityTypeWeek {
					this.WelfData.Task[v.GetId()] = &model.TaskData{}
				}
			}
		}
	}
	// 重置周任务
}

func (this *Player) GetName() string {
	return this.Name
}

func (this *Player) setName(newName string) string {
	this.Name = newName
	return this.Name
}

func (this *Player) GetIP() string {
	return this.Ip
}

func (this *Player) CreateScene(sceneId, gameId, gameMode, sceneMode int, numOfGames int32, params []int32, dbGameFree *server_proto.DB_GameFree) (*Scene, hall_proto.OpResultCode_Game) {
	gs := GameSessMgrSington.GetMinLoadSess(gameId)
	if gs == nil {
		logger.Logger.Warnf("(this *Player) EnterScene %v, %v GameSessMgrSington.GetMinLoadSess() = nil ", this.SnId, gameId)
		return nil, hall_proto.OpResultCode_Game_OPRC_SceneServerMaintain_Game
	}

	s := SceneMgrSingleton.CreateScene(0, this.SnId, sceneId, gameId, gameMode, sceneMode, 1, numOfGames, params, gs, this.GetPlatform(), 0, dbGameFree, dbGameFree.GetId())
	if s == nil {
		logger.Logger.Tracef("(this *Player) EnterScene %v, SceneMgrSingleton.CreateScene() = nil ", this.SnId)
		return nil, hall_proto.OpResultCode_Game_OPRC_Error_Game
	}
	return s, hall_proto.OpResultCode_Game_OPRC_Sucess_Game
}

func (this *Player) CreateLocalGameScene(sceneId, gameId, gameSite, sceneMode, playerNum int, params []int32,
	dbGameFree *server_proto.DB_GameFree, baseScore, groupId int32) (*Scene, hall_proto.OpResultCode_Game) {
	gs := GameSessMgrSington.GetMinLoadSess(gameId)
	if gs == nil {
		logger.Logger.Warnf("(this *Player) CreateLocalGameScene %v, %v GameSessMgrSington.GetMinLoadSess() = nil ", this.SnId, gameId)
		return nil, hall_proto.OpResultCode_Game_OPRC_SceneServerMaintain_Game
	}

	s := SceneMgrSingleton.CreateLocalGameScene(this.SnId, sceneId, gameId, gameSite, sceneMode, 1, params, gs,
		this.GetPlatform(), playerNum, dbGameFree, baseScore, groupId, dbGameFree.GetId())
	if s == nil {
		logger.Logger.Tracef("(this *Player) EnterScene %v, SceneMgrSingleton.CreateScene() = nil ", this.SnId)
		return nil, hall_proto.OpResultCode_Game_OPRC_Error_Game
	}
	return s, hall_proto.OpResultCode_Game_OPRC_Sucess_Game
}

func (this *Player) EnterScene(s *Scene, ischangeroom bool, pos int) bool {
	if s == nil {
		logger.Logger.Tracef("(this *Player) EnterScene, s == nil %v", this.SnId)
		return false
	}

	if s != nil {
		this.applyPos = -1
		if s.PlayerEnter(this, pos, ischangeroom) {
			FirePlayerEnterScene(this, s)
			return true
		}
	}

	return false
}

func (this *Player) ReturnScene(isLoaded bool) *Scene {
	logger.Logger.Tracef("(this *Player) ReturnScene %v", this.SnId)
	if this.scene == nil {
		logger.Logger.Warnf("(this *Player) ReturnScene this.scene == nil snid:%d", this.SnId)
		return nil
	}
	if !this.scene.HasPlayer(this) && !this.scene.HasAudience(this) {
		logger.Logger.Warnf("(this *Player) ReturnScene !this.scene.HasPlayer(this) && !this.scene.HasAudience(this) snid:%d", this.SnId)
		return nil
	}

	pack := &server_proto.WGPlayerReturn{
		PlayerId: proto.Int32(this.SnId),
		IsLoaded: proto.Bool(isLoaded),
		RoomId:   proto.Int(this.scene.sceneId),
	}
	ctx := this.scene.GetPlayerGameCtx(this.SnId)
	if ctx != nil {
		pack.EnterTs = proto.Int64(ctx.enterTs)
	}
	proto.SetDefaults(pack)
	if this.SendToGame(int(server_proto.SSPacketID_PACKET_WG_PLAYERRETURN), pack) {
		//比赛场返场检查
		//MatchMgrSington.OnPlayerReturnScene(this.scene, this)
		return this.scene
	}
	//不应该这这里处理，因为 miniGame中小游戏玩家 player.Scene是不存在的。
	//FirePlayerReturnScene(this)

	return nil
}

func (this *Player) BackDiffData() {
	this.diffData.Coin = this.Coin
	this.diffData.SafeBoxCoin = this.SafeBoxCoin
}

func (this *Player) UpdateVip() {
	if this.IsRob {
		return
	}
	this.VIP = this.GetVIPLevel(this.CoinPayTotal)
	//clubManager.UpdateVip(this)
}

func (this *Player) AddMoneyPayTotal(amount int64) {
	if amount > 0 {
		this.MoneyPayTotal += amount
		this.SendDiffData() //更新vip
	}
}

func (this *Player) SendDiffData() {
	this.UpdateVip()
	var dirty bool
	pack := &player_proto.SCPlayerDataUpdate{}
	pack.UpdateField = 0
	//金币
	if this.diffData.Coin != this.Coin {
		dirty = true
		pack.Coin = proto.Int64(this.Coin)
		this.diffData.Coin = this.Coin
		pack.UpdateField += UpdateField_Coin
	}
	//钻石
	if this.diffData.Diamond != this.Diamond {
		dirty = true
		pack.Diamond = proto.Int64(this.Diamond)
		this.diffData.Diamond = this.Diamond
		pack.UpdateField += UpdateField_Diamond
	}
	//保险箱金币
	if this.diffData.SafeBoxCoin != this.SafeBoxCoin {
		dirty = true
		pack.SafeBoxCoin = proto.Int64(this.SafeBoxCoin)
		this.diffData.SafeBoxCoin = this.SafeBoxCoin
		pack.UpdateField += UpdateField_SafeBoxCoin
	}
	//VIP等级
	if this.diffData.VIP != this.VIP {
		dirty = true
		pack.Vip = proto.Int32(this.VIP)
		this.diffData.VIP = this.VIP
		pack.UpdateField += UpdateField_VIP
	}
	//手机积分
	if this.diffData.PhoneScore != this.PhoneScore {
		dirty = true
		pack.PhoneScore = this.PhoneScore
		this.diffData.PhoneScore = this.PhoneScore
		pack.UpdateField += UpdateField_PhoneScore
	}
	// 邀请积分
	if this.diffData.InviteScore != this.InviteScore {
		dirty = true
		pack.InviteScore = this.InviteScore
		this.diffData.InviteScore = this.InviteScore
		pack.UpdateField += UpdateField_InviteScore
	}
	//总充值金额
	if this.diffData.CoinPayTotal != this.CoinPayTotal {
		dirty = true
		pack.CoinPayTotal = proto.Int64(this.CoinPayTotal)
		this.diffData.CoinPayTotal = this.CoinPayTotal
		pack.UpdateField += UpdateField_CoinPayTotal
	}
	//流水差异
	if this.diffData.TotalConvertibleFlow != this.TotalConvertibleFlow {
		dirty = true
		pack.TotalConvertibleFlow = proto.Int64(this.TotalConvertibleFlow)
		this.diffData.TotalConvertibleFlow = this.TotalConvertibleFlow
		pack.UpdateField += UpdateField_TotalConvertibleFlow
	}
	//比赛报名券
	if this.diffData.Ticket != this.Ticket {
		dirty = true
		pack.Ticket = proto.Int64(this.Ticket)
		this.diffData.Ticket = this.Ticket
		pack.UpdateField += UpdateField_Ticket
	}
	//积分
	if this.diffData.Grade != this.Grade {
		dirty = true
		pack.Grade = proto.Int64(this.Grade)
		this.diffData.Grade = this.Grade
		pack.UpdateField += UpdateField_Grade
	}
	//象棋积分
	if this.diffData.ChessGrade != this.ChessGrade {
		dirty = true
		pack.ChessGrade = proto.Int64(this.ChessGrade)
		this.diffData.ChessGrade = this.ChessGrade
		pack.UpdateField += UpdateField_ChessGrade
	}
	// 排位积分
	if this.diffData.RankScore == nil {
		this.diffData.RankScore = make(map[int32]int64)
	}
	if p := RankMgrSingleton.GetPlayerSeason(this.SnId); p != nil {
		for k := range p.RankType {
			if this.diffData.RankScore[k] != p.RankType[k].Score {
				dirty = true
				if pack.RankScore == nil {
					pack.RankScore = make(map[int32]int64)
				}
				pack.RankScore[k] = proto.Int64(p.RankType[k].Score)
				this.diffData.RankScore[k] = p.RankType[k].Score
				pack.UpdateField += UpdateField_RankScore
			}
		}
	}
	if len(pack.RankScore) == 0 {
		pack.RankScore = nil
	}

	if dirty {
		FriendMgrSington.UpdateInfo(this.Platform, this.SnId)
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PLAYERDATAUPDATE), pack)
		logger.Logger.Trace("(this *Player) SendDiffData() ", pack)
	}
}

func GetExchangeFlow(pd *model.PlayerData) int32 {
	if pd == nil {
		return 0
	}

	platform := PlatformMgrSingleton.GetPlatform(pd.Platform)
	if platform != nil {
		if (platform.ExchangeFlag & ExchangeFlag_Flow) != 0 {
			key, err := GetPromoterKey(pd.PromoterTree, pd.BeUnderAgentCode, pd.Channel)
			if err == nil {
				cfg := PromoterMgrSington.GetConfig(key)
				if cfg != nil {
					if (cfg.ExchangeFlag & ExchangeFlag_Flow) != 0 {
						return cfg.ExchangeFlow
					}
				}
			}
			return platform.ExchangeFlow
		}
	}
	return 0
}

func GetExchangeGiveFlow(pd *model.PlayerData) int32 {
	if pd == nil {
		return 0
	}

	platform := PlatformMgrSingleton.GetPlatform(pd.Platform)
	if platform != nil {
		if (platform.ExchangeFlag & ExchangeFlag_Flow) != 0 {
			key, err := GetPromoterKey(pd.PromoterTree, pd.BeUnderAgentCode, pd.Channel)
			if err == nil {
				cfg := PromoterMgrSington.GetConfig(key)
				if cfg != nil {
					if (cfg.ExchangeFlag & ExchangeFlag_Flow) != 0 {
						return cfg.ExchangeGiveFlow
					}
				}
			}
			return platform.ExchangeGiveFlow
		}
	}
	return 0
}

func GetExchangeForceTax(pd *model.PlayerData) int32 {
	if pd == nil {
		return 0
	}

	platform := PlatformMgrSingleton.GetPlatform(pd.Platform)
	if platform != nil {
		if (platform.ExchangeFlag & ExchangeFlag_Force) != 0 {
			key, err := GetPromoterKey(pd.PromoterTree, pd.BeUnderAgentCode, pd.Channel)
			if err == nil {
				cfg := PromoterMgrSington.GetConfig(key)
				if cfg != nil {
					if (cfg.ExchangeFlag & ExchangeFlag_Force) != 0 {
						return cfg.ExchangeForceTax
					}
				}
			}
			return platform.ExchangeForceTax
		}
	}
	return 0
}

func GetExchangeTax(pd *model.PlayerData) int32 {
	if pd == nil {
		return 0
	}

	platform := PlatformMgrSingleton.GetPlatform(pd.Platform)
	if platform != nil {
		if (platform.ExchangeFlag & ExchangeFlag_Tax) != 0 {
			key, err := GetPromoterKey(pd.PromoterTree, pd.BeUnderAgentCode, pd.Channel)
			if err == nil {
				cfg := PromoterMgrSington.GetConfig(key)
				if cfg != nil {
					if (cfg.ExchangeFlag & ExchangeFlag_Tax) != 0 {
						return cfg.ExchangeTax
					}
				}
			}
			return platform.ExchangeTax
		}
	}
	return 0
}

func GetExchangeFlag(pd *model.PlayerData) int32 {
	if pd == nil {
		return 0
	}

	platform := PlatformMgrSingleton.GetPlatform(pd.Platform)
	if platform != nil {
		if (platform.ExchangeFlag & ExchangeFlag_Flow) != 0 {
			key, err := GetPromoterKey(pd.PromoterTree, pd.BeUnderAgentCode, pd.Channel)
			if err == nil {
				cfg := PromoterMgrSington.GetConfig(key)
				if cfg != nil {
					if (cfg.ExchangeFlag & ExchangeFlag_Flow) != 0 {
						return 2
					}
				}
			}
			return 1
		}
	}
	return 0
}

func (this *Player) GetRegisterPrize() int32 {
	platform := this.GetPlatform()
	key, err := this.GetPromoterKey()
	var cfg *PromoterConfig
	if err == nil {
		cfg = PromoterMgrSington.GetConfig(key)
	}

	return GGetRegisterPrize(platform, cfg)
}

func GGetRegisterPrize(platform *Platform, cfg *PromoterConfig) int32 {
	if platform != nil {
		if cfg != nil {
			if (cfg.ExchangeFlag & ExchangeFlag_UpAcc) != 0 {
				return cfg.NewAccountGiveCoin
			}
		}
		return platform.NewAccountGiveCoin
	}
	return 0
}

func (this *Player) GetUpdateAccPrize() int32 {
	platform := this.GetPlatform()
	key, err := this.GetPromoterKey()
	var cfg *PromoterConfig
	if err == nil {
		cfg = PromoterMgrSington.GetConfig(key)
	}

	return GGetUpdateAccPrize(platform, cfg)
}

func GGetUpdateAccPrize(platform *Platform, cfg *PromoterConfig) int32 {
	if platform != nil {
		if cfg != nil {
			if (cfg.ExchangeFlag & ExchangeFlag_UpAcc) != 0 {
				return cfg.UpgradeAccountGiveCoin
			}
		}
		return platform.UpgradeAccountGiveCoin
	}
	return 0
}

func (this *Player) GetPromoterKey() (string, error) {
	return GetPromoterKey(this.PromoterTree, this.BeUnderAgentCode, this.Channel)
}

//计算流水可以兑换的值  返回 还需要多少流水 赠送扣除 强制费用 合计流水
//func GetExchangeFlowTotal(pd *model.PlayerData, playerTotalFlow int64, givesInfo []*model.CoinGiveLog) (int64,
//	int64, int64, int64) {
//	//可兑换的流水
//	var flow int64
//
//	var giveLostCoin int64  //赠送扣除
//	var forceTax int64      //强制费用
//	var needTotalFlow int64 //需要的流水
//	var lockCoin int64      //多少金额无法兑换，如果兑换需要强制扣除行政费用
//
//	retIds := []string{}
//	retAllIds := []string{}
//
//	exchangeFlow := GetExchangeFlow(pd)
//	exchangeGiveFlow := GetExchangeGiveFlow(pd)
//	exchangeForceTax := GetExchangeForceTax(pd)
//
//	if GetExchangeFlag(pd) > 0 {
//
//		//逐笔计算兑换流水金额，从上到下
//		curTotalFlow := playerTotalFlow
//
//		//按照时间排序
//		sort.Slice(givesInfo, func(i, j int) bool { return givesInfo[i].Ts > givesInfo[j].Ts })
//
//		for i := 0; i < len(givesInfo); i++ {
//			info := givesInfo[i]
//			if info.Ts > pd.LastExchangeTime {
//				retAllIds = append(retAllIds, info.LogId.Hex())
//				//计算是否通过稽核
//				needFlow := int64(0)
//				curTotalFlow += info.FLow
//				//如果是系统赠送的，需要全部扣除
//				if info.RecType == model.COINGIVETYPE_SYSTEM {
//					exchangeGiveFlowS := exchangeGiveFlow
//					t := ActMgrSington.GetExchangeFlow(pd.Platform, info.LogType)
//					if t != 0 {
//						exchangeGiveFlowS = t
//					}
//
//					if info.NeedGiveFlowRate > 0 {
//						exchangeGiveFlowS = info.NeedGiveFlowRate
//					}
//
//					needFlow = int64(math.Floor(float64(info.GiveCoin)*float64(exchangeGiveFlowS)/100)) * 100
//
//					if curTotalFlow < needFlow {
//						//需要扣除
//						giveLostCoin += info.GiveCoin
//						lockCoin += info.GiveCoin
//						flow += needFlow - curTotalFlow
//						curTotalFlow = 0
//					} else {
//						curTotalFlow -= needFlow
//						retIds = append(retIds, info.LogId.Hex())
//					}
//				} else {
//					exchangeGiveFlowS := exchangeGiveFlow
//					t := ActMgrSington.GetExchangeFlow(pd.Platform, info.LogType)
//					if t != 0 {
//						exchangeGiveFlowS = t
//					}
//					if info.NeedGiveFlowRate > 0 {
//						exchangeGiveFlowS = info.NeedGiveFlowRate
//					}
//
//					exchangePayFlowS := exchangeFlow
//					if info.NeedFlowRate > 0 {
//						exchangePayFlowS = info.NeedFlowRate
//					}
//
//					//分两部分扣除
//					needFlow = int64(math.Floor(float64(info.GiveCoin)*float64(exchangeGiveFlowS)/100)) * 100
//					needFlow += int64(math.Floor(float64(info.PayCoin)*float64(exchangePayFlowS)/100)) * 100
//					if curTotalFlow < needFlow {
//						//需要扣除
//						giveLostCoin += info.GiveCoin
//						//强制费用
//						forceTax += info.PayCoin * int64(exchangeForceTax) / 10000
//						lockCoin += info.GiveCoin
//						lockCoin += info.PayCoin
//						flow += needFlow - curTotalFlow
//						curTotalFlow = 0
//					} else {
//						curTotalFlow -= needFlow
//						retIds = append(retIds, info.LogId.Hex())
//					}
//				}
//				needTotalFlow += needFlow
//			}
//		}
//	}
//
//	return flow, giveLostCoin, forceTax, needTotalFlow
//}
//
////pageNo 1开始
//func GetExchangeFlowTotalPacket(playerTotalFlow int64, givesInfo []*model.CoinGiveLog, pd *model.PlayerData,
//	pageNo, pageNum int32, isCheck bool) *shop_proto.SCGetPlayerPayFlowList {
//	pack := &shop_proto.SCGetPlayerPayFlowList{}
//	var giveLostCoin int64  //赠送扣除
//	var forceTax int64      //强制费用
//	var needTotalFlow int64 //需要的流水
//	startIndex := (pageNo - 1) * pageNum
//	endIndex := pageNo * pageNum
//	//platform := this.GetPlatform()
//	exchangeFlow := GetExchangeFlow(pd)
//	exchangeGiveFlow := GetExchangeGiveFlow(pd)
//	exchangeForceTax := GetExchangeForceTax(pd)
//
//	//按照时间排序
//	sort.Slice(givesInfo, func(i, j int) bool { return givesInfo[i].Ts > givesInfo[j].Ts })
//	//逐笔计算兑换流水金额，从上到下p
//	curTotalFlow := playerTotalFlow
//
//	index := int32(0)
//
//	if GetExchangeFlag(pd) > 0 {
//		for i := 0; i < len(givesInfo); i++ {
//			info := givesInfo[i]
//			if isCheck || info.Ts > pd.LastExchangeTime {
//				tInfo := &shop_proto.PlayerPayFlowLog{}
//				tInfo.Ts = proto.Int64(info.Ts)
//				tInfo.PayType = proto.Int32(info.RecType)
//				tInfo.PayCoin = proto.Int64(info.PayCoin)
//				tInfo.GiveCoin = proto.Int64(info.GiveCoin)
//				tInfo.FinishFlow = proto.Int64(info.FLow)
//				tInfo.OrderID = proto.String(info.LogId.Hex())
//				//计算是否通过稽核
//				needFlow := int64(0)
//				isPass := int32(0)
//				curTotalFlow += info.FLow
//				//如果是系统赠送的，需要全部扣除
//				if info.RecType == model.COINGIVETYPE_SYSTEM {
//					exchangeGiveFlowS := exchangeGiveFlow
//					t := ActMgrSington.GetExchangeFlow(pd.Platform, info.LogType)
//					if t != 0 {
//						exchangeGiveFlowS = t
//					}
//					if info.NeedGiveFlowRate > 0 {
//						exchangeGiveFlowS = info.NeedGiveFlowRate
//					}
//					needFlow = int64(math.Floor(float64(info.GiveCoin)*float64(exchangeGiveFlowS)/100)) * 100
//					tInfo.GiveNeedFlow = proto.Int64(needFlow)
//					if curTotalFlow < needFlow {
//						//需要扣除
//						giveLostCoin += info.GiveCoin
//						tInfo.ForceGiveCoin = proto.Int64(info.GiveCoin)
//
//						curTotalFlow = 0
//					} else {
//						curTotalFlow -= needFlow
//						isPass = 1
//					}
//				} else {
//					exchangeGiveFlowS := exchangeGiveFlow
//					t := ActMgrSington.GetExchangeFlow(pd.Platform, info.LogType)
//					if t != 0 {
//						exchangeGiveFlowS = t
//					}
//
//					if info.NeedGiveFlowRate > 0 {
//						exchangeGiveFlowS = info.NeedGiveFlowRate
//					}
//					exchangePayFlowS := exchangeFlow
//					if info.NeedFlowRate > 0 {
//						exchangePayFlowS = info.NeedFlowRate
//					}
//					//分两部分扣除
//					needFlow = int64(math.Floor(float64(info.GiveCoin)*float64(exchangeGiveFlowS)/100)) * 100
//					tInfo.GiveNeedFlow = proto.Int64(needFlow)
//
//					payNeedFlow := int64(math.Floor(float64(info.PayCoin)*float64(exchangePayFlowS)/100)) * 100
//					tInfo.PayNeedFlow = proto.Int64(payNeedFlow)
//					needFlow += payNeedFlow
//
//					if curTotalFlow < needFlow {
//						//需要扣除
//						giveLostCoin += info.GiveCoin
//						tInfo.ForceGiveCoin = proto.Int64(info.GiveCoin)
//
//						//强制费用
//						forceTax += info.PayCoin * int64(exchangeForceTax) / 10000
//						tInfo.ForceTax = proto.Int64(info.PayCoin * int64(exchangeForceTax) / 10000)
//						curTotalFlow = 0
//					} else {
//						curTotalFlow -= needFlow
//						isPass = 1
//					}
//				}
//
//				tInfo.IsPass = proto.Int32(isPass)
//				needTotalFlow += needFlow
//
//				if index >= startIndex && index < endIndex {
//					pack.Data = append(pack.Data, tInfo)
//				}
//
//				index += 1
//			}
//		}
//	}
//	pack.PageNo = proto.Int32(int32(pageNo))
//	pack.PageSum = proto.Int32(int32(math.Ceil(float64(index) / float64(pageNum))))
//	pack.PageSize = proto.Int32(pageNum)
//	pack.TotalNum = proto.Int32(index)
//	proto.SetDefaults(pack)
//	return pack
//}

func (this *Player) SendPlayerInfo() {
	this.UpdateVip()
	scPlayerData := &player_proto.SCPlayerData{
		OpRetCode: player_proto.OpResultCode_OPRC_Sucess,
		Data: &player_proto.PlayerData{
			AccId:         proto.String(this.AccountId),        //账号ID
			Platform:      proto.String(this.Platform),         //平台
			Channel:       proto.String(this.Channel),          //渠道
			Promoter:      proto.String(this.BeUnderAgentCode), //推广员
			Name:          proto.String(this.Name),             //名字
			SnId:          proto.Int32(this.SnId),              //数字账号
			Head:          proto.Int32(this.Head),              //头像
			Sex:           proto.Int32(this.Sex),               //性别
			GMLevel:       proto.Int32(this.GMLevel),           //GM等级
			Coin:          proto.Int64(this.Coin),              //金币
			SpecailFlag:   proto.Int32(int32(this.Flags)),      //特殊标记
			Tel:           proto.String(this.Tel),              //手机号码
			InviterId:     proto.Int32(this.InviterId),         //邀请人ID
			SafeBoxCoin:   proto.Int64(this.SafeBoxCoin),       //保险箱金币
			VIP:           proto.Int32(this.VIP),               //VIP帐号
			AlipayAccount: proto.String(this.AlipayAccount),    //支付宝账号
			AlipayAccName: proto.String(this.AlipayAccName),    //支付宝实名
			Bank:          proto.String(this.Bank),             //银行
			BankAccount:   proto.String(this.BankAccount),      //银行帐号
			BankAccName:   proto.String(this.BankAccName),      //银行开户名
			HeadOutLine:   proto.Int32(this.HeadOutLine),       //头像框
			CoinPayTotal:  proto.Int64(this.CoinPayTotal),      //总充值金额
			CreateTs:      proto.Int64(this.CreateTime.Unix()), //角色创建时间
			//ClubCoin:      proto.Int64(this.ClubCoin),          //俱乐部金币
			Ticket:  proto.Int64(this.Ticket),  //比赛入场券
			Grade:   proto.Int64(this.Grade),   //积分
			Diamond: proto.Int64(this.Diamond), //钻石
			HeadUrl: proto.String(this.HeadUrl),
			//VipExp:  proto.Int64(this.GetCurrentVIPExp()),
			ChessGrade:          proto.Int64(this.ChessGrade),
			RankScore:           make(map[int32]int64),
			UnMaxPower:          proto.Int64(this.UnMaxPower),
			PowerList:           this.PowerList,
			FishLevel:           proto.Int64(this.FishLevel),
			FishExp:             proto.Int64(this.FishExp),
			VipShopRefreshCount: proto.Int32(this.VipShopRefreshCount),
			Signature:           this.Signature,
			Age:                 this.Age,
		},
	}
	if this.Roles != nil {
		scPlayerData.Data.UseRoleId = this.Roles.ModId
	}
	if this.Pets != nil {
		scPlayerData.Data.UsePetId = this.Pets.ModId
	}
	if this.WelfData != nil {
		scPlayerData.Data.ReliefFundTimes = this.WelfData.ReliefFundTimes
	}
	if item := BagMgrSingleton.GetItem(this.SnId, VCard); item != nil {
		scPlayerData.Data.VCoin = int64(item.ItemNum) //V卡

	}

	// 排位积分
	scPlayerData.Data.RankScore = RankMgrSingleton.GetPlayerRankScore(this.SnId)

	raw := fmt.Sprintf("%v%v", model.DEFAULT_PLAYER_SAFEBOX_PWD, common.GetAppId())
	h := md5.New()
	io.WriteString(h, raw)
	pwd := hex.EncodeToString(h.Sum(nil))

	if this.SafeBoxPassword != pwd {
		scPlayerData.Data.SafeBoxIsExist = proto.Int32(1)
	} else {
		scPlayerData.Data.SafeBoxIsExist = proto.Int32(0)
	}

	if this.scene != nil {
		scPlayerData.RoomId = proto.Int(this.scene.sceneId)
		scPlayerData.GameId = proto.Int(this.scene.gameId)
		//增加gameFreeId
		scPlayerData.LogicId = this.scene.dbGameFree.Id
	}
	platform := PlatformMgrSingleton.GetPlatform(this.Platform)
	if platform != nil {
		scPlayerData.BindOption = proto.Int32(platform.BindOption)
	} else {
		scPlayerData.BindOption = proto.Int32(7)
	}

	proto.SetDefaults(scPlayerData)
	logger.Logger.Tracef("Send SCPlayerData %v", scPlayerData)
	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PLAYERDATA), scPlayerData)

	if !this.IsRob {
		this.SyncPlayerDataToGateSrv(this.PlayerData)
	}

	// 判断玩家是否在游戏内
	if this.scene != nil && this.thrscene == 0 {
		this.SendGameConfig(int32(this.scene.gameId), this.Platform, this.Channel)
	}

	PetMgrSington.CheckShowRed(this)

	//this.SendJackpotInfo()
}

//func (this *Player) SendJackpotInfo() {
//	//通知所有的gamesrv向玩家发送奖池信息
//	if this.gateSess != nil {
//		var gateSid int64
//		if srvInfo, ok := this.gateSess.GetAttribute(srvlib.SessionAttributeServerInfo).(*srvlibproto.SSSrvRegiste); ok && srvInfo != nil {
//			sessionId := srvlib.NewSessionIdEx(srvInfo.GetAreaId(), srvInfo.GetType(), srvInfo.GetId(), 0)
//			gateSid = sessionId.Get()
//		}
//
//		//查找当前平台下所以开放的游戏id
//		info := make([]*server_proto.GameInfo, 0)
//		gps := PlatformMgrSingleton.GetGameFrees(this.Platform)
//		for _, v := range gps {
//			if v.Status {
//				if v.DbGameFree.GetGameRule() != 0 {
//					//lgi := &server_proto.GameInfo{
//					//	GameId:     proto.Int32(v.DbGameFree.GetGameId()),
//					//	GameFreeId: proto.Int32(v.DbGameFree.GetId()),
//					//	GameType:   proto.Int32(v.DbGameFree.GetGameType()),
//					//}
//					info = append(info, &server_proto.GameInfo{
//						GameId:     proto.Int32(v.DbGameFree.GetGameId()),
//						GameFreeId: proto.Int32(v.DbGameFree.GetId()),
//						GameType:   proto.Int32(v.DbGameFree.GetGameType()),
//					})
//				}
//			}
//		}
//
//		servers := GameSessMgrSington.GetAllGameSess()
//		for _, v := range servers {
//			pack := &server_proto.WGGameJackpot{
//				Sid:      this.sid,
//				GateSid:  gateSid,
//				Platform: this.Platform,
//				Info:     info,
//			}
//			v.Send(int(server_proto.SSPacketID_PACKET_WG_GAMEJACKPOT), pack)
//		}
//	}
//}

func (this *Player) IsGM() bool {
	if this.GMLevel > 0 {
		return true
	}
	return false
}

func (this *Player) IsAgentor() bool {
	return false
}

func (this *Player) IsPlayer() bool {
	return true
}

func (this *Player) HasAuthority(role int) bool {
	switch role {
	case common.ClientRole_Agentor:
		return this.IsAgentor()
	case common.ClientRole_GM:
		return this.IsGM()
	case common.ClientRole_Player:
		return true
	}
	return false
}

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
	}
}

func (this *Player) ReportLoginEvent() {
	//用户登录
	if !this.IsRob {
		isBindPhone := int32(0)
		if this.Tel != "" {
			isBindPhone = 1
			if this.UpgradeTime.IsZero() {
				this.UpgradeTime = this.CreateTime
			}
		}
		LogChannelSingleton.WriteMQData(model.GenerateLogin(model.CreatePlayerLoginEvent(this.SnId,
			this.Channel, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, this.Ip,
			this.CreateTime, this.UpgradeTime, isBindPhone, this.TelephonePromoter, this.DeviceId)))
		//登录通知
		//ActMonitorMgrSington.SendActMonitorEvent(ActState_Login, this.SnId, this.Name, this.Platform,
		//	0, 0, "", 0)
	}
}

func (this *Player) ReportBindPhoneEvent() {
	//升级账号事件
	if !this.IsRob {
		//LogChannelSingleton.WriteMQData(model.GenerateBindEvent(model.CreatePlayerBindPhoneEvent(
		//	this.SnId, this.Channel, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS,
		//	this.CreateTime, this.TelephonePromoter)))
	}
}

func (this *Player) ReportBindAlipayEvent() {
	//绑定支付宝事件
	//if !this.IsRob {
	//	d, e := model.MarshalPlayerBindAlipayEvent(2, this.SnId, this.Channel, this.BeUnderAgentCode,
	//		this.Platform, this.City, this.DeviceOS, this.TelephonePromoter)
	//	if e == nil {
	//		rmd := model.NewInfluxDBData("hj.player_bind_alipay", d)
	//		if rmd != nil {
	//			InfluxDBDataChannelSington.Write(rmd)
	//		}
	//	}
	//}
}

func (this *Player) AddCoinGiveLog(payCoin, giveCoin int64, coinType, logType, recType int32, remark, oper string) {
	plt := PlatformMgrSingleton.GetPlatform(this.Platform)
	curVer := int32(0)
	if plt != nil {
		curVer = plt.ExchangeVer
	}

	log := model.NewCoinGiveLogEx(this.SnId, this.Name, payCoin, giveCoin, coinType, logType, this.PromoterTree,
		recType, curVer, this.Platform, this.Channel, this.BeUnderAgentCode, remark, oper, this.PackageID, 0, 0)
	if log != nil {
		task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
			err := model.InsertGiveCoinLog(log)
			if err == nil {
				if this.LastExchangeOrder != "" && this.TotalConvertibleFlow > 0 {
					err = model.UpdateGiveCoinLastFlow(log.Platform, this.LastExchangeOrder, this.TotalConvertibleFlow)
				}
			}
			return err
		}), task.CompleteNotifyWrapper(func(ud interface{}, t task.Task) {
			if ud == nil {
				//清空流水，更新id
				this.TotalConvertibleFlow = 0
				this.LastExchangeOrder = log.LogId.Hex()
			}
		}), "UpdateGiveCoinLastFlow").StartByGroupFixExecutor(log.Platform, "UpdateGiveCoinLastFlow")
	}
}

func ReportSystemGiveEvent(pd *model.PlayerData, amount, tag int32, notifyClient bool) {
	//系统赠送
	if !pd.IsRob {
		//插入本地表
		if amount > 0 {
			if ActMgrSington.GetIsNeedGive(pd.Platform, tag) {
				plt := PlatformMgrSingleton.GetPlatform(pd.Platform)
				curVer := int32(0)
				if plt != nil {
					curVer = plt.ExchangeVer
				}

				log := model.NewCoinGiveLogEx(pd.SnId, pd.Name, 0, int64(amount), 0, tag, pd.PromoterTree,
					model.COINGIVETYPE_SYSTEM, curVer, pd.Platform, pd.Channel, pd.BeUnderAgentCode, "",
					"system", pd.PackageID, 0, 0)
				if log != nil {
					task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
						err := model.InsertGiveCoinLog(log)
						if err == nil {
							if pd.LastExchangeOrder != "" && pd.TotalConvertibleFlow > 0 {
								err = model.UpdateGiveCoinLastFlow(log.Platform, pd.LastExchangeOrder, pd.TotalConvertibleFlow)
							}
						}
						return err
					}), task.CompleteNotifyWrapper(func(ud interface{}, t task.Task) {
						if ud == nil {
							//清空流水，更新id
							pd.TotalConvertibleFlow = 0
							pd.LastExchangeOrder = log.LogId.Hex()
							player := PlayerMgrSington.GetPlayerBySnId(pd.SnId)
							if player == nil {
								//需要回写数据库
								task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
									model.UpdatePlayerExchageFlowAndOrder(pd.Platform, pd.SnId, 0, pd.LastExchangeOrder)
									return nil
								}), nil, "UpdatePlayerExchageFlowAndOrder").StartByGroupFixExecutor(log.Platform, pd.AccountId)
							}
						}
					}), "UpdateGiveCoinLastFlow").StartByGroupFixExecutor(log.Platform, "UpdateGiveCoinLastFlow")
				}
			}

			if notifyClient {
				player := PlayerMgrSington.GetPlayerBySnId(pd.SnId)
				if player != nil {
					//通知客户端
					sendPack := &shop_proto.SCNotifyGiveCoinInfo{
						GiveCoin: proto.Int64(int64(amount)),
						GiveTag:  proto.Int32(tag),
					}

					proto.SetDefaults(sendPack)
					player.SendToClient(int(shop_proto.SPacketID_SHOP_SC_GIVECOIN_INFO), sendPack)
				}
			}
		}
	}
}

func (this *Player) ReportSystemGiveEvent(amount, tag int32, notifyClient bool) {
	ReportSystemGiveEvent(this.PlayerData, amount, tag, notifyClient)
}

// 破产事件
func (this *Player) ReportBankRuptcy(gameid, gamemode, gamefreeid int32) {
	//if !this.IsRob {
	//	d, e := model.MarshalBankruptcyEvent(2, this.SnId, this.TelephonePromoter, this.Channel, this.BeUnderAgentCode,
	//		this.Platform, this.City, this.CreateTime, gameid, gamemode, gamefreeid)
	//	if e == nil {
	//		rmd := model.NewInfluxDBData("hj.player_bankruptcy", d)
	//		if rmd != nil {
	//			InfluxDBDataChannelSington.Write(rmd)
	//		}
	//	}
	//}
}

func (this *Player) CheckType(gameid, gamefreeId int32) *server_proto.DB_PlayerType {
	types := srvdata.PlayerTypeMgrSington.GetPlayerType(gamefreeId)
	cnt := len(types)
	if cnt > 0 {
		var pgs model.PlayerGameStatics
		if this.GDatas != nil {
			if d, exist := this.GDatas[strconv.Itoa(int(gameid))]; exist {
				pgs = d.Statics
			}
		}

		//赔率 产出/投入 万分比
		odds := int64(float64(float64(pgs.TotalOut+1)/float64(pgs.TotalIn+1)) * 10000)
		if odds > 10000000 {
			odds = 10000000
		}
		for i := 0; i < cnt; i++ {
			t := types[i]
			logger.Logger.Warn("Player CheckType 0  ", this.CoinPayTotal, t.GetPayLowerLimit(), t.GetPayUpperLimit(), pgs.GameTimes,
				t.GetGameTimeLowerLimit(), t.GetGameTimeUpperLimit(), pgs.TotalIn, t.GetTotalInLowerLimit(), t.GetTotalInUpperLimit(),
				odds, t.GetOddsLowerLimit(), t.GetOddsUpperLimit())
			if t != nil {
				if this.CoinPayTotal >= int64(t.GetPayLowerLimit()) && this.CoinPayTotal <= int64(t.GetPayUpperLimit()) &&
					pgs.GameTimes >= int64(t.GetGameTimeLowerLimit()) && pgs.GameTimes <= int64(t.GetGameTimeUpperLimit()) &&
					pgs.TotalIn >= int64(t.GetTotalInLowerLimit()) && pgs.TotalIn <= int64(t.GetTotalInUpperLimit()) &&
					odds >= int64(t.GetOddsLowerLimit()) && odds <= int64(t.GetOddsUpperLimit()) {
					return t
				}
			}
		}
	}
	return nil
}

// 线程不安全，避免异步任务调用
func (this *Player) GetPlatform() *Platform {
	platform := PlatformMgrSingleton.GetPlatform(this.Platform)
	if platform != nil && platform.Isolated {
		return platform
	}
	return PlatformMgrSingleton.GetPlatform(DefaultPlatform)
}

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) PlayerMacAbnormal() bool {
	return false //s.HasSameIp(p.Ip) || s.HasSameMac() || s.HasSameTel() || s.HasSamePostion()
}

// 这个冲账记录不可随便写,需要加该日志时，请找lyk确认,暂定依据是金币直接加到身上，不依赖其他数据状态的可以写该日志
// 业务准则:先更新标记，再写冲账记录
func (this *Player) AddPayCoinLog(coin int64, coinType int32, oper string) {
	ts := time.Now().UnixNano()
	billNo := ts
	log := model.NewPayCoinLog(billNo, this.SnId, coin, 0, oper, coinType, 0)
	if log != nil {
		ts = log.TimeStamp
		task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
			err := model.InsertPayCoinLog(this.Platform, log)
			if err != nil {
				logger.Logger.Errorf("InsertPayCoinLog err:%v log:%v", err, log)
				return err
			}
			return err
		}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
			switch coinType {
			case model.PayCoinLogType_Coin:
				if this.CoinPayTs < ts {
					this.CoinPayTs = ts
					this.dirty = true
				}
			case model.PayCoinLogType_SafeBoxCoin:
				if this.SafeBoxCoinTs < ts {
					this.SafeBoxCoinTs = ts
					this.dirty = true
				}
			}
		}), "InsertPayCoinLog").StartByFixExecutor("InsertPayCoinLog")
	}
}

// 充值回调
func (this *Player) SendPlayerRechargeAnswer(coin int64) {
	if this.Tel == "" {
		pack := &player_proto.SCPlayerRechargeAnswer{
			OpParam:     proto.Int64(1),
			AddCoin:     proto.Int64(coin),
			Coin:        proto.Int64(this.Coin),
			SafeBoxCoin: proto.Int64(this.SafeBoxCoin),
		}
		proto.SetDefaults(pack)
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PLAYERRECHARGEANSWER), pack)
	}
}

//
//// 在线奖励: 重置, 清零在线时长及奖励领取信息
//func (this *Player) OnlineRewardReset() {
//	this.PlayerData.OnlineRewardData.OnlineDuration = 0
//	this.PlayerData.OnlineRewardData.RewardReceived = 0
//	this.PlayerData.OnlineRewardData.Ts = time.Now().Unix()
//	this.dirty = true
//}
//
//// 在线奖励: （Logout时）累计在线时长
//func (this *Player) OnlineRewardAddUpOnlineDuration() {
//	if this.state != PlayerState_Online {
//		return
//	}
//
//	tNow := time.Now()
//	inSameDay := common.InSameDay(tNow, time.Unix(this.PlayerData.OnlineRewardData.Ts, 0))
//	if inSameDay {
//		this.PlayerData.OnlineRewardData.OnlineDuration += uint32(tNow.Unix() - this.PlayerData.OnlineRewardData.Ts)
//	} else {
//		this.PlayerData.OnlineRewardData.OnlineDuration = uint32(tNow.Unix() - now.New(tNow).BeginningOfDay().Unix())
//	}
//
//	this.PlayerData.OnlineRewardData.Ts = tNow.Unix()
//	this.dirty = true
//}
//
//// 在线奖励: (实时)获取在线时长
//func (this *Player) OnlineRewardGetOnlineDuration() uint32 {
//	this.OnlineRewardAddUpOnlineDuration()
//	return this.PlayerData.OnlineRewardData.OnlineDuration
//}

// 幸运转盘
//func (this *Player) LuckyTurntableSwitchScore(continuous bool) {
//	if continuous {
//		this.PlayerData.LuckyTurnTableData.Score = this.PlayerData.LuckyTurnTableData.TomorrowScore +
//			int64(this.PlayerData.LuckyTurnTableData.TomorrowFloatScore/100)
//	} else {
//		this.PlayerData.LuckyTurnTableData.Score = 0
//	}
//
//	this.PlayerData.LuckyTurnTableData.TomorrowScore = 0
//	this.PlayerData.LuckyTurnTableData.TomorrowFloatScore = 0
//	this.dirty = true
//}

func (this *Player) SyncSafeBoxCoinToGame() {
	pack := &server_proto.WGSyncPlayerSafeBoxCoin{
		SnId:        proto.Int32(this.SnId),
		SafeBoxCoin: proto.Int64(this.SafeBoxCoin),
	}
	proto.SetDefaults(pack)
	this.SendToGame(int(server_proto.SSPacketID_PACKET_WG_SyncPlayerSafeBoxCoin), pack)
}

//func (this *Player) GetDgHboPlayerName(plt *Platform) (string, string) {
//	if plt == nil {
//		return "", ""
//	}
//	if plt.DgHboConfig == 0 {
//		return this.DgGame, this.DgPass
//	} else if plt.DgHboConfig == 1 {
//		return this.StoreDgGame, this.StoreDgPass
//	} else if plt.DgHboConfig == 2 {
//		return this.StoreHboGame, this.StoreHboPass
//	}
//	return "", ""
//}
//
//func (this *Player) SetDgHboPlayerName(plt *Platform, name, pass string) {
//	if plt == nil {
//		return
//	}
//
//	if plt.DgHboConfig == 0 {
//		this.DgGame = name
//		this.DgPass = pass
//		if strings.Contains(name, "dg") {
//			this.StoreDgGame = name
//			this.StoreDgPass = pass
//		} else {
//			this.StoreHboGame = name
//			this.StoreHboPass = pass
//		}
//	} else if plt.DgHboConfig == 1 {
//		this.StoreDgGame = name
//		this.StoreDgPass = pass
//	} else if plt.DgHboConfig == 2 {
//		this.StoreHboGame = name
//		this.StoreHboPass = pass
//	}
//
//}

func (this *Player) AddCoinPayTotal(coin int64) {
	this.CoinPayTotal += coin
}

// 当用户充值
func OnPlayerPay(pd *model.PlayerData, coin int64) {
	if pd == nil {
		return
	}

	buf, err := pd.GetPlayerDataEncoder()
	if err == nil {
		pack := &server_proto.WTPlayerPay{
			AddCoin:    proto.Int64(coin),
			PlayerData: buf.Bytes(),
		}
		proto.SetDefaults(pack)
		common.SendToActThrSrv(int(server_proto.SSPacketID_PACKET_WT_PLAYERPAY), pack)
	}

	//ActFPayMgrSington.OnPlayerPay(pd.SnId, pd.Platform, coin)
}

func (this *Player) SendPlatformCanUsePromoterBind() {
	state := int32(0)
	plt := PlatformMgrSingleton.GetPlatform(this.Platform)
	if plt != nil {
		if plt.IsCanUserBindPromoter {
			state = 1
			if this.BeUnderAgentCode != "" && this.BeUnderAgentCode != "0" {
				state = 2
			}
		}
	}

	pack := &player_proto.SCBindPromoterState{
		BindState: proto.Int32(state),
	}

	proto.SetDefaults(pack)
	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_BINDPROMOTERSTATE), pack)
}

func (this *Player) RedirectByGame(packetid int, rawpack interface{}) bool {
	if this.scene == nil || this.scene.gameSess == nil || this.scene.gameSess.Session == nil {
		logger.Logger.Tracef("[%v] sess == nil ", this.Name)
		return false
	}
	if rawpack == nil {
		logger.Logger.Trace(" rawpack == nil ")
		return false
	}

	data, err := netlib.MarshalPacket(packetid, rawpack)
	if err == nil {
		pack := &server_proto.SSRedirectToPlayer{
			SnId:     proto.Int32(this.SnId),
			PacketId: proto.Int(packetid),
			Data:     data,
		}
		proto.SetDefaults(pack)
		return this.SendToGame(int(server_proto.SSPacketID_PACKET_SS_REDIRECTTOPLAYER), pack)
	}
	return false
}

//	func (this *Player) GetMatchAr(matchId int32) *model.MatchAchievement {
//		if this.MatchAchievement == nil {
//			this.MatchAchievement = make(map[int32]*model.MatchAchievement)
//		}
//		if ar, exist := this.MatchAchievement[matchId]; exist {
//			return ar
//		}
//		ar := &model.MatchAchievement{MatchId: matchId, CreateTs: int32(time.Now().Unix())}
//		this.MatchAchievement[matchId] = ar
//		return ar
//	}
//func (this *Player) InitLayered() {
//	logger.Logger.Trace("(this *Player) InitLayered")
//	if this.IsRob {
//		return
//	}
//	this.layered = make(map[int]bool)
//	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
//		return LogicLevelMgrSington.SendPostBySnIds(this.Platform, []int32{this.SnId})
//	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
//		if data != nil {
//			newData := data.([]NewMsg)
//			for _, d := range newData {
//				cnf := LogicLevelMgrSington.GetConfig(d.Platform)
//				if cnf == nil {
//					continue
//				}
//				this.layerlevels = d.Levels
//				for _, v := range d.Levels {
//					if td, ok := cnf.LogicLevelInfo[int32(v)]; ok {
//						if td.StartAct == 1 {
//							for _, id := range td.CheckActIds {
//								this.layered[int(id)] = true
//							}
//						}
//					}
//				}
//			}
//		}
//		//this.ActStateSend2Client()
//	}), "SendPostBySnIds").Start()
//	////
//	for k, v := range this.layered {
//		logger.Logger.Tracef("InitLayered....id=%v   %v", k, v)
//	}
//
//}

func (this *Player) ActStateSend2Client() {
	logger.Logger.Trace("(this *Player) ActStateSend2Client")
	actSwitchCfg := make([]int32, common.ActId_Max)
	for i := 0; i < common.ActId_Max; i++ {
		isOpen := true
		switch i {
		//case common.ActId_OnlineReward:
		//	cfg, ok := ActOnlineRewardMgrSington.Configs[this.Platform]
		//	if !ok || cfg.StartAct <= 0 {
		//		isOpen = false
		//	}
		//case common.ActId_GoldTask:
		//	plateFormConfig := ActGoldTaskMgrSington.GetPlateFormConfig(this.Platform)
		//	if plateFormConfig == nil || plateFormConfig.StartAct == 0 {
		//		isOpen = false
		//	}
		//case common.ActId_GoldCome:
		//	plateFormConfig := ActGoldComeMgrSington.GetPlateFormConfig(this.Platform)
		//	if plateFormConfig == nil || plateFormConfig.StartAct == 0 {
		//		isOpen = false
		//	}
		//case common.ActId_LuckyTurntable:
		//	cfg, ok := ActLuckyTurntableMgrSington.Configs[this.Platform]
		//	if !ok || cfg == nil || cfg.StartAct <= 0 {
		//		isOpen = false
		//	}
		//case common.ActId_Yeb:
		//	cfg, ok := ActYebMgrSington.Configs[this.Platform]
		//	if !ok || cfg == nil || cfg.StartAct <= 0 {
		//		isOpen = false
		//	}
		//case common.ActId_Card:
		//	cfg, ok := ActCardMgrSington.Configs[this.Platform]
		//	if !ok || cfg == nil || cfg.StartAct <= 0 {
		//		isOpen = false
		//	}
		case common.ActId_RebateTask:
			rebateTask := RebateInfoMgrSington.rebateTask[this.Platform]
			if rebateTask != nil && !rebateTask.RebateSwitch {
				isOpen = false
			}
		//case common.ActId_VipLevelBonus:
		//	config := ActVipMgrSington.GetConfig(this.Platform)
		//	if config == nil || config.StartAct == 0 {
		//		isOpen = false
		//	}
		//case common.ActId_Sign:
		//	config := ActSignMgrSington.GetConfig(this.Platform)
		//	if config == nil || config.StartAct == 0 {
		//		isOpen = false
		//	}
		//case common.ActId_Task:
		//	config := ActTaskMgrSington.GetPlatformConfig(this.Platform)
		//	if config == nil || config.StartAct == 0 {
		//		isOpen = false
		//	}
		case common.ExchangeId_Bank:
			platform := PlatformMgrSingleton.GetPlatform(this.Platform)
			if platform == nil || !platform.IsMarkFlag(int32(BindBackCard)) {
				isOpen = false
			}
		case common.ExchangeId_Alipay:
			platform := PlatformMgrSingleton.GetPlatform(this.Platform)
			if platform == nil || !platform.IsMarkFlag(int32(BindAlipay)) {
				isOpen = false
			}
		case common.ExchangeId_Wechat:
			platform := PlatformMgrSingleton.GetPlatform(this.Platform)
			if platform == nil || !platform.IsMarkFlag(int32(BindWeiXin)) {
				isOpen = false
			}
		}

		if !isOpen {
			actSwitchCfg[i] = 1
			continue
		}

		open, ok := this.layered[i]
		if ok && open {
			actSwitchCfg[i] = 1
		}
	}
	pack := &login_proto.SCActSwitchCfg{
		ActSwitchCfg: actSwitchCfg, // 0开 1关 默认开
	}
	proto.SetDefaults(pack)
	logger.Logger.Trace("ActStateSend2Client: ", this.SnId, pack)
	this.SendToClient(int(login_proto.LoginPacketID_PACKET_SC_ACTSWITCHCFG), pack)
}

func (this *Player) ModifyActSwitch() {
	logger.Logger.Trace("====================ModifyActSwitch==================")

	//this.ActStateSend2Client()
}

// SyncPlayerDataToGateSrv 玩家信息同步到网关
func (this *Player) SyncPlayerDataToGateSrv(pd *model.PlayerData) {
	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	err := enc.Encode(pd)
	if err != nil {
		logger.Logger.Info("(this *Player) UpdateToGateSrv gob.Marshal error", err)
	} else {
		pack := &server_proto.WRPlayerData{
			Sid:        this.sid,
			PlayerData: buf.Bytes(),
		}
		proto.SetDefaults(pack)
		this.gateSess.Send(int(server_proto.SSPacketID_PACKET_WR_PlayerData), pack)
	}
}

func (this *Player) BindGroupTag(tags []string) {
	if this.gateSess == nil {
		return
	}
	pack := &server_proto.SGBindGroupTag{
		Sid:  proto.Int64(this.sid),
		Code: server_proto.SGBindGroupTag_OpCode_Add,
		Tags: tags,
	}
	proto.SetDefaults(pack)
	this.gateSess.Send(int(server_proto.SSPacketID_PACKET_SG_BINDGROUPTAG), pack)
}

func (this *Player) UnBindGroupTag(tags []string) {
	if this.gateSess == nil {
		return
	}
	pack := &server_proto.SGBindGroupTag{
		Sid:  proto.Int64(this.sid),
		Code: server_proto.SGBindGroupTag_OpCode_Del,
		Tags: tags,
	}
	proto.SetDefaults(pack)
	this.gateSess.Send(int(server_proto.SSPacketID_PACKET_SG_BINDGROUPTAG), pack)
}

func (this *Player) TryRetrieveLostGameCoin(sceneid int) {
	//发送一个探针,等待ack后同步金币
	logProbe := model.NewCoinLog()
	logProbe.SnId = this.SnId
	logProbe.Count = 0     //必须是0,探针标识
	logProbe.RestCount = 0 //this.Coin
	logProbe.SeqNo = this.GameCoinTs
	logProbe.RoomId = int32(sceneid)
	LogChannelSingleton.WriteLog(logProbe)
	//先把玩家身上的钱清掉
	//this.Coin = 0
	this.SendDiffData()
}

func (this *Player) SyncGameCoin(sceneid int, enterts int64) {
	//游服金币冲账
	endts := time.Now().UnixNano()
	var err error
	var gamecoinlogs []model.CoinWAL
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		gamecoinlogs, err = model.GetCoinWALBySnidAndInGameAndGreaterTs(this.Platform, this.SnId, int32(sceneid), enterts)
		return err
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if err == nil && len(gamecoinlogs) != 0 {
			oldCoin := this.Coin
			var cnt int64
			for i := 0; i < len(gamecoinlogs); i++ {
				ts := gamecoinlogs[i].Ts
				if ts >= enterts && ts <= endts {
					cnt = gamecoinlogs[i].Count
					this.Coin += cnt
					if ts > this.GameCoinTs {
						this.GameCoinTs = ts
					}
				}
			}
			newCoin := this.Coin
			newTs := this.GameCoinTs
			logger.Logger.Warnf("PlayerData(%v) SyncGameCoin before:enterts=%v before:Coin=%v after:GameCoinTs=%v after:Coin=%v", this.SnId, enterts, oldCoin, newTs, newCoin)
		}
		this.SendDiffData()
	}), "GetCoinWALBySnidAndInGameAndGreaterTs").Start()
}
func (this *Player) SendShowRed(showType hall_proto.ShowRedCode, showChild, isShow int32) {
	pack := &hall_proto.SCShowRed{
		ShowRed: &hall_proto.ShowRed{
			ShowType:  showType,
			ShowChild: proto.Int32(showChild),
			IsShow:    proto.Int32(isShow),
		},
	}
	proto.SetDefaults(pack)
	//logger.Logger.Trace("SCShowRed:", pack)
	this.SendToClient(int(hall_proto.HallPacketID_PACKET_SC_SHOWRED), pack)
}

func (this *Player) SCVIPBuy(buy int64) {
	//buy *= 10000
	//this.AddMoneyPayTotal(buy)
	//this.GetVIPLevel(0) // 更新下vip等级
	pack := &player_proto.SCVIPBuy{
		OpRetCode: player_proto.OpResultCode_OPRC_Sucess,
	}
	pack.TolVipExp, pack.Money = this.GetCurrentVIPExp() // 获取经验会更新vip等级
	pack.Vip = this.VIP
	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_VIPBUY), pack)
}

func (this *Player) SCVIPInfo() {
	if this.IsRob {
		return
	}

	pack := &player_proto.SCVIPInfo{
		OpRetCode: player_proto.OpResultCode_OPRC_Error,
	}

	vips := VipMgrSington.GetVIPcfg(this.Platform)
	if vips != nil {
		pack.MoneyRatio = int32(vips.MoneyRatio)
		for _, cfg := range vips.List {
			data := &player_proto.VIPcfg{
				VipId:           cfg.VipId,
				VipEx:           cfg.VipEx,
				Price:           cfg.Price,
				Privilege1:      cfg.Privilege1,
				Privilege2:      cfg.Privilege2,
				Privilege3:      cfg.Privilege3,
				Privilege4:      cfg.Privilege4,
				Privilege5:      cfg.Privilege5,
				Privilege6:      cfg.Privilege6,
				Privilege7Price: cfg.Privilege7Price,
				Privilege8:      cfg.Privilege8,
				LineId:          cfg.RewardOutlineID,
				ShopId2:         cfg.ShopId2,
				ShopId7:         cfg.ShopId7,
			}
			for itemId, itemNum := range cfg.Award {
				data.Item = append(data.Item, &player_proto.ItemInfo{
					ItemId:  int32(itemId),
					ItemNum: itemNum,
				})
			}
			for itemId, itemNum := range cfg.Privilege7 {
				data.Privilege7 = append(data.Privilege7, &player_proto.ItemInfo{
					ItemId:  int32(itemId),
					ItemNum: itemNum,
				})
			}
			data.BagStatus = make([]int32, 3)
			data.BagStatus[0] = 0                                                  //每日礼包 0可领取 1不可领取  只能领取当前VIP等级的
			data.BagStatus[1] = 0                                                  //每日金币礼包 0可领取 1不可领取 只能领取当前VIP等级的
			data.BagStatus[2] = this.GetPlayerVipBagStatus(cfg.ShopId7, cfg.VipId) //固定VIP礼包 0可领取 1不可领取 可以领取所有VIP等级的奖励
			if cfg.VipId != this.VIP {
				data.BagStatus[0] = 1 //每日礼包 0可领取 1不可领取  只能领取当前VIP等级的
				data.BagStatus[1] = 1 //每日金币礼包 0可领取 1不可领取 只能领取当前VIP等级的
			} else {
				data.BagStatus[0] = this.GetPlayerVipBagStatus(0, cfg.VipId)
				data.BagStatus[1] = this.GetPlayerVipBagStatus(cfg.ShopId2, cfg.VipId)
			}
			pack.List = append(pack.List, data)
		}

		pack.TolVipExp, pack.Money = this.GetCurrentVIPExp(vips)
		pack.Vip = this.VIP
		pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess
		//WelfareMgrSington.MonitorWelfData(this)
		//pack.VipId = append(pack.VipId, this.WelfData.VIPGift...)
	}
	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_VIPINFO), pack)
}
func (this *Player) GetVIPExpByPay(payTotal int32) int32 {
	vips := VipMgrSington.GetVIPcfg(this.Platform)
	return int32(math.Floor(float64(payTotal) * vips.MoneyRatio / 100))
}
func (this *Player) VIPDraw(id int32) {
	//WelfareMgrSington.MonitorWelfData(this)
	pack := &player_proto.SCVIPDraw{
		Id:        id,
		OpRetCode: player_proto.OpResultCode_OPRC_Error,
	}
	if id != 0 {
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_DRAWVIPGIFT), pack)
		return
	}
	if this.WelfData.VIPBag == nil {
		this.WelfData.VIPBag = make(map[int32]map[int32]int32)
	}
	if innerMap, ok := this.WelfData.VIPBag[this.VIP]; ok {
		if _, ok := innerMap[0]; ok {
			logger.Logger.Trace("VIPDraw VIP is repeat id%v ", id)
			this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_DRAWVIPGIFT), pack)
			return
		}
	} else {
		this.WelfData.VIPBag[this.VIP] = make(map[int32]int32)
	}

	vips := VipMgrSington.GetVIPcfg(this.Platform)
	if vips != nil {
		for _, data := range vips.List {
			if data.VipId == this.VIP {
				pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess
				this.WelfData.VIPBag[this.VIP][0] = 1
				//金币数量
				money := data.Privilege1[0]
				//vip经验
				addVipExp := int64(float64(data.Privilege1[1]) / vips.MoneyRatio)
				this.AddCoin(int64(money), 0, common.GainWay_VIPGift, "sys", "VIP每日礼包")
				this.AddMoneyPayTotal(addVipExp)
				pack.Vip = this.VIP
				logger.Logger.Tracef("玩家领取VIP每日礼包成功！snid = %v,Vip = %v,金币数量 = %v，addVipEx = %v", this.SnId, this.VIP, money, addVipExp)
				//VIP礼包统计数据
				task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
					var item []model.ItemInfo
					item = append(item, model.ItemInfo{ItemId: 1, ItemNum: int64(money)})
					log := model.NewDbVip(this.Platform, this.SnId, this.VIP, 0, 0, 0, item, 0, "Vip每日礼包")
					return model.InsertDbVipLog(log)
				}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
					if data != nil {
						logger.Logger.Errorf("err:", data.(error))
					}
				}), "VIPDraw").Start()
				break
			}
		}
	}

	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_DRAWVIPGIFT), pack)

}

func (this *Player) GetCurrentVIPExp(vipcfg ...*webapi_proto.VIPcfgDataList) (exp int64, money int64) {
	var vips *webapi_proto.VIPcfgDataList
	if len(vipcfg) == 0 {
		vips = VipMgrSington.GetVIPcfg(this.Platform)
	} else {
		vips = vipcfg[0]
	}
	exp = int64(float64(this.MoneyPayTotal) * vips.MoneyRatio)
	tolexp := int32(0)
	oldVipLevel := this.VIP
	if vips != nil && this.MoneyPayTotal != 0 {
		allExp := int64(float64(this.MoneyPayTotal) * vips.MoneyRatio)
		for _, v := range vips.List {
			tolexp = v.VipEx
			if allExp >= int64(v.VipEx) {
				this.VIP = v.VipId
				this.VipExtra = v.Privilege4
			} else {
				break
			}
		}
	}
	money = int64(tolexp) - exp
	if money < 0 {
		money = 0
	}
	if oldVipLevel != this.VIP {
		//玩家VIP升级
		this.SCVIPInfo()
		logger.Logger.Trace("VIP升级！")
	}
	return // 默认
}

func (this *Player) GetVIPLevel(CoinPayTotal int64) int32 {
	if this.IsRob {
		return 0
	}
	vips := VipMgrSington.GetVIPcfg(this.Platform)
	vip := int32(0)
	if vips != nil && this.MoneyPayTotal != 0 {
		allExp := int64(float64(this.MoneyPayTotal) * vips.MoneyRatio)
		for _, v := range vips.List {
			if allExp >= int64(v.VipEx) {
				vip = v.VipId
				this.VipExtra = v.Privilege4
			} else {
				break
			}
		}
	}
	if vip != this.VIP {
		//玩家VIP升级
		this.SCVIPInfo()
		logger.Logger.Trace("VIP升级！")
	}
	this.VIP = vip
	return this.VIP
}

func (this *Player) GetMaxVIPLevel() int32 {

	vips := VipMgrSington.GetVIPcfg(this.Platform)
	if vips != nil && len(vips.List) > 0 {
		vn := len(vips.List) - 1

		return vips.List[vn].VipId
	}
	return 0
}

// 特权1 VIP比赛场免费次数  策划说暂时没了
func (this *Player) GetVIPPrivilege1() int32 {
	/*	cfg := VipMgrSington.GetVIPLevelCfg(this.Platform, this.VIP)
		if cfg != nil {
			return cfg.Privilege1
		}*/
	return 0
}

// 玩家登录 检查充值状态
func (this *Player) GetPayGoodsInfo() {
	if this.IsRob {
		return
	}
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		info := model.GetDbShopLogsByState(this.Platform, this.SnId)
		if info != nil {
			for _, shop := range info {
				err := model.UpdateDbShopState(shop.Platform, shop.LogId.Hex(), 1)
				if err != nil {
					logger.Logger.Error("GetPayGoodsInfo.UpdateDbShopState err:", err)
					return nil
				}
			}
		}
		return info
	}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
		if data != nil {
			infos := data.([]*model.DbShop)
			for _, info := range infos {
				var itemInfo []*player_proto.PayItem
				var items []*Item
				if len(info.Amount) > 0 {
					this.AddCoin(int64(info.Amount[0]), 0, info.GainWay, "Callback_login", info.Remark)
					this.AddDiamond(int64(info.Amount[1]), 0, info.GainWay, "Callback_login", info.Remark)
				}
				this.AddMoneyPayTotal(int64(info.ConsumeNum))
				if info.ItemInfo != nil {
					for _, v := range info.ItemInfo {
						items = append(items, &Item{ItemId: v.ItemId, ItemNum: v.ItemNum})
						itemInfo = append(itemInfo, &player_proto.PayItem{
							ItemId:  v.ItemId,
							ItemNum: v.ItemNum,
						})
					}
				}
				switch info.Remark {
				case "BlindBox":
					if len(info.OtherParams) > 0 {
						this.WelfData.BlindBoxId = info.OtherParams[0]
					} else {
						logger.Logger.Errorf("GetPayGoodsInfo BlindBox OtherParams is nil")
					}
				case "FirstRecharge":
					if len(info.OtherParams) > 0 {

						this.WelfData.FirstPayDay = info.OtherParams[0]
						this.WelfData.FirstPayTickets = info.Ts
					} else {
						logger.Logger.Errorf("GetPayGoodsInfo FirstRecharge OtherParams is nil")
					}
				case "ContinuousPay":
					if len(info.OtherParams) > 0 {

						this.WelfData.ContinuousPayDay = info.OtherParams[0]
						this.WelfData.ContinuousPayTickets = info.Ts
					} else {
						logger.Logger.Errorf("GetPayGoodsInfo ContinuousPay OtherParams is nil")
					}
				}
				this.UpdatePlayerVipBag(info.ShopId)
				this.UpdateShopID(info.ShopId)

				this.dirty = true
				this.SendDiffData()

				info.Amount[2] = this.GetVIPExpByPay(info.ConsumeNum)

				BagMgrSingleton.AddJybBagInfo(this, items, 0, info.GainWay, info.Operator, info.Remark)

				PayGoodsInfo := &player_proto.SCPayGoodsInfo{
					Gold: info.Amount,
					Item: itemInfo,
				}
				proto.SetDefaults(PayGoodsInfo)
				this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PAYGOODSINFO), PayGoodsInfo)
				TaskSubjectSingleton.Touch(common.TaskTypePay, &TaskData{
					SnId: this.SnId,
					Num:  int64(info.ConsumeNum),
				})
			}
		}

	})).StartByFixExecutor("GetPayGoodsLogs")
}

func (this *Player) SendJackPotInit() {
	var pack = &hall_proto.SCHundredSceneGetGameJackpot{}
	gameFreeIds := []int32{
		3010001, 3010002, 3010003, 3010004,
		3020001, 3020002, 3020003, 3020004,
		3030001, 3030002, 3030003, 3030004,
		3040001, 3040002, 3040003,
		3050001, 3050002, 3050003}
	for _, id := range gameFreeIds {
		data := srvdata.PBDB_GameFreeMgr.GetData(id)
		if data != nil && len(data.Jackpot) > 0 {
			jpfi := &hall_proto.GameJackpotFundInfo{
				GameFreeId:  proto.Int32(data.Id),
				JackPotFund: proto.Int64(int64(data.BaseScore * data.Jackpot[0])),
			}
			pack.GameJackpotFund = append(pack.GameJackpotFund, jpfi)
		}
	}
	if len(pack.GameJackpotFund) > 0 {
		this.SendToClient(int(hall_proto.HundredScenePacketID_PACKET_SC_GAMEJACKPOT), pack)
	}
}

func (this *Player) OnlineLogLogin() {
	if this.IsRob {
		return
	}
	if this.onlineLog == nil {
		this.onlineLog = model.NewOnlineLog(bson.NewObjectId(), this.SnId, common.LoginLogTypeLogin, this.Platform)
		LogChannelSingleton.WriteLog(*this.onlineLog)
	}
}

func (this *Player) OnlineLogRehold() {
	if this.IsRob {
		return
	}
	if this.onlineLog == nil {
		this.onlineLog = model.NewOnlineLog(bson.NewObjectId(), this.SnId, common.LoginLogTypeRehold, this.Platform)
		LogChannelSingleton.WriteLog(*this.onlineLog)
	}
}

func (this *Player) OnlineLogDrop() {
	if this.IsRob {
		return
	}
	if this.onlineLog != nil && this.onlineLog.OfflineTs == 0 {
		this.onlineLog.OfflineType = common.LoginLogTypeDrop
		this.onlineLog.OfflineTs = time.Now().Unix()
		LogChannelSingleton.WriteLog(*this.onlineLog)
		this.onlineLog = nil
	}
}

func (this *Player) OnlineLogLogout() {
	if this.IsRob {
		return
	}
	if this.onlineLog != nil && this.onlineLog.OfflineTs == 0 {
		this.onlineLog.OfflineType = common.LoginLogTypeLogout
		this.onlineLog.OfflineTs = time.Now().Unix()
		LogChannelSingleton.WriteLog(*this.onlineLog)
		this.onlineLog = nil
	}
}

func (this *Player) AddDiamondToCoin(n int64) {
	if n > 0 {
		this.dirty = true
		this.DiamondToCoin += n
	}
}

// SendRankSeason 通知客户端赛季信息
func (this *Player) SendRankSeason() {
	pack := &rankmatch.SCRMSeasonInfo{}
	cfg := RankMgrSingleton.GetSeasonConfig(this.Platform)
	if cfg == nil {
		this.SendToClient(int(rankmatch.RankMatch_PACKET_RM_SCRMSeasonInfo), pack)
		return
	}

	pack = &rankmatch.SCRMSeasonInfo{
		Id:        cfg.SeasonId,
		TimeStamp: []int64{cfg.StartTs, cfg.EndTs},
	}

	rank := RankMgrSingleton.GetPlayerSeason(this.SnId)
	if rank != nil && rank.PlayerRankSeason != nil && rank.RankType != nil {
		for k, v := range rank.RankType {
			if v == nil {
				continue
			}
			info := &rankmatch.SeasonInfo{Id: k}
			info.Lv, info.Score = RankMgrSingleton.GetPlayerRankLV(k, this.SnId)
			info.LastLv, info.LastScore = RankMgrSingleton.GetPlayerLastRankLV(k, this.SnId)
			pack.Seasons = append(pack.Seasons, info)
		}
	}
	this.SendToClient(int(rankmatch.RankMatch_PACKET_RM_SCRMSeasonInfo), pack)
	logger.Logger.Trace("SCTMSeasonInfo:", pack)
}

func (this *Player) SendPlayerCoin() {
	LogChannelSingleton.WriteLog(&model.RankPlayerCoin{
		Platform: this.Platform,
		SnId:     this.SnId,
		Name:     this.Name,
		Sex:      this.Sex,
		HeadUrl:  this.HeadUrl,
		Coin:     this.GetTotalCoin(),
		ModId:    this.GetRoleId(),
	})
}

// 解锁炮倍
func (this *Player) UnPlayerPowerEx(power int64) {
	logger.Logger.Tracef("解锁炮倍 当前最大解锁炮倍：%v,要解锁的炮倍：%v", this.UnMaxPower, power)
	if this.UnPlayerPower(power) {
		pack := &player_proto.SCPlayerUnPower{
			UnMaxpower: power,
		}
		this.UnMaxPower = power
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PlayerUnPower), pack)
		logger.Logger.Tracef("通知客户端解锁最大炮倍,snid = %v,power = %v", this.SnId, power)
	}
}

// 道具解锁炮台
func (this *Player) ItemUnPlayerPowerListEx(itemId int32) {
	if itemId == 0 {
		return
	}
	//判断炮台存不存在
	var powerId int32 = 0
	for _, data := range srvdata.PBDB_ArtillerySkinMgr.Datas.GetArr() {
		if data.CannonId == itemId {
			powerId = data.Id
			break
		}
	}
	if powerId == 0 {
		return
	}

	if this.UnPlayerPowerList(powerId) {
		//通知客户端解锁炮台
		pack := &player_proto.SCPlayerUnPowerList{
			UnPowerList: powerId,
		}
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PlayerUnPowerList), pack)
		logger.Logger.Trace("通知客户端解锁炮台 snid = %v,解锁的炮台：%v,当前已有的炮台 = %v", this.SnId, powerId, this.PowerList)
	}
}

// powerId 解锁炮台
func (this *Player) UnPlayerPowerListEx(powerId int32) {
	data := srvdata.PBDB_ArtillerySkinMgr.GetData(powerId)
	if data == nil {
		return
	}
	if this.UnPlayerPowerList(powerId) {
		//通知客户端解锁炮台
		pack := &player_proto.SCPlayerUnPowerList{
			UnPowerList: powerId,
		}
		this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PlayerUnPowerList), pack)
		logger.Logger.Trace("通知客户端解锁炮台 snid = %v,解锁的炮台：%v,当前已有的炮台 = %v", this.SnId, powerId, this.PowerList)
	}
}
func (this *Player) UpdatePlayerVipBag(shopId int32) {
	//判断是否是vip商品 更新数据
	shopInfo := ShopMgrSington.GetShopInfo(shopId, this)
	if shopInfo != nil {
		if shopInfo.Page == ShopPagePrivilege {
			if this.WelfData.VIPBag == nil {
				this.WelfData.VIPBag = make(map[int32]map[int32]int32)
			}
			if _, ok := this.WelfData.VIPBag[shopInfo.VipLevel]; !ok {
				this.WelfData.VIPBag[shopInfo.VipLevel] = make(map[int32]int32)
			}
			this.WelfData.VIPBag[shopInfo.VipLevel][shopInfo.Id] = shopInfo.Type
			logger.Logger.Tracef("玩家购买VIP商品成功,更新购买状态！snid = %v shopId = %v,VIP = %v", this.SnId, shopInfo.Id, shopInfo.VipLevel)
			pack := &player_proto.SCVIPDraw{
				Id:        shopInfo.Type,
				Vip:       shopInfo.VipLevel,
				OpRetCode: player_proto.OpResultCode_OPRC_Sucess,
			}
			this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_DRAWVIPGIFT), pack)
			//VIP金币礼包&VIP固定礼包统计数据
			task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
				var item []model.ItemInfo
				item = append(item, model.ItemInfo{ItemId: shopInfo.Type, ItemNum: shopInfo.Amount})
				log := model.NewDbVip(this.Platform, this.SnId, shopInfo.VipLevel, shopInfo.Type, shopInfo.ConstType, int64(shopInfo.CostArea[0]), item, shopInfo.Id, shopInfo.Name)
				return model.InsertDbVipLog(log)
			}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
				if data != nil {
					logger.Logger.Errorf("err:", data.(error))
				}
			}), "UpdatePlayerVipBag").Start()
		}
	}
}

// 判断vip特权某个礼包是否领取过 返回值：0可领取 1 不可领取
func (this *Player) GetPlayerVipBagStatus(shopId, vipLevel int32) int32 {
	if vipLevel > this.VIP {
		return 1
	}
	if this.WelfData == nil || this.WelfData.VIPBag == nil {
		return 0
	}
	if _, ok := this.WelfData.VIPBag[vipLevel]; !ok {
		return 0
	}
	if _, ok := this.WelfData.VIPBag[vipLevel][shopId]; !ok {
		return 0
	}
	return 1
}

func (this *Player) UpdateVipShopData() {
	this.VipShopData = nil
	this.VipShopRefreshCount = 0
	//每日礼包 和每日金币礼包需要初始化
	if this.WelfData != nil && this.WelfData.VIPBag != nil {
		delKeyList := []int32{}
		for _, data := range this.WelfData.VIPBag {
			for shopId, shopType := range data {
				if shopId == 0 {
					//初始化每日礼包
					delKeyList = append(delKeyList, shopId)
					logger.Logger.Trace("初始化VIP每日礼包！！！！！！！")
				} else {
					if shopType == 1 {
						delKeyList = append(delKeyList, shopId)
						logger.Logger.Trace("初始化VIP每日固定礼包！！！！！！！！！！")
					}
				}
			}
		}
		for _, delKey := range delKeyList {
			for _, data := range this.WelfData.VIPBag {
				delete(data, delKey)
			}
		}
		this.SCVIPInfo()
	}
}

func (this *Player) RandRobotVip(scene *Scene) {
	if !this.IsRobot() || scene == nil || scene.dbGameFree == nil {
		return
	}
	// vip
	config := srvdata.PBDB_PotOddMgr.GetData(scene.dbGameFree.GetId())
	if config == nil || len(config.VipOdd) == 0 {
		return
	}
	var all int32
	for _, v := range config.VipOdd {
		all += v
	}
	n := rand.Int31n(all)
	vip := 0
	var sum int32
	for k, v := range config.VipOdd {
		sum += v
		if n < sum {
			vip = k
			break
		}
	}
	this.VIP = int32(vip)
}

// BindTelReward 发送绑定手机号奖励
func (this *Player) BindTelReward() {
	// todo 奖励限额；ip日期最多赠送多少奖励
	// 发送奖励
	plt := PlatformMgrSingleton.GetPlatform(this.Platform)
	if plt != nil {
		var items []*Item
		for k, v := range plt.BindTelReward {
			switch k {
			case 1:
				items = append(items, &Item{
					ItemId:  common.ItemIDCoin,
					ItemNum: v,
				})
			case 2:
				items = append(items, &Item{
					ItemId:  common.ItemIDDiamond,
					ItemNum: v,
				})
			default:
				items = append(items, &Item{
					ItemId:  k,
					ItemNum: v,
				})
			}

		}
		BagMgrSingleton.AddJybBagInfo(this, items, 0, common.GainWay_BindTel, "system", "绑定手机号")
	}
}

func (this *Player) UpdateShopID(shopId int32) {
	var shopInfo *ShopInfo
	if shops, ok := ShopMgrSington.ShopInfos[this.Platform]; ok {
		if shopInf, ok := shops[shopId]; ok {
			shopInfo = shopInf
		}
	}
	if shopInfo != nil && shopInfo.FirstSwitch {
		if !slices.Contains(this.ShopID, int(shopInfo.Id)) {
			this.ShopID = append(this.ShopID, int(shopInfo.Id))
		}
	}
}

// 增加抽奖次数
func (this *Player) addLotteryCount(count int32) {
	if WelfareMgrSington.GetPhoneLotteryStatus(this.Platform) == WelfareClose {
		return
	}
	this.LotteryCount += count
	if this.LotteryCount < 0 {
		this.LotteryCount = 0
	}
	if this.LotteryCount >= math.MaxInt32 {
		this.LotteryCount = math.MaxInt32
	}
	//通知客户端
	pack := &player_proto.SCPhoneLotteryCount{
		Count: this.LotteryCount,
	}
	this.SendToClient(int(player_proto.PlayerPacketID_PACKET_SC_PhoneLotteryCount), pack)

}

// 增加手机积分
func (this *Player) AddPhoneScore(num, add int64, gainWay int32, oper, remark string) {
	if num == 0 {
		return
	}
	if WelfareMgrSington.GetPhoneLotteryStatus(this.Platform) == WelfareClose {
		return
	}
	logger.Logger.Tracef("snid(%v)  AddPhoneScore(%v)", this.SnId, num)
	if num != 0 /*&& !async*/ {
		this.dirty = true
		if num > 0 {
			this.PhoneScore += num
		} else {
			if -num > this.PhoneScore {
				logger.Logger.Errorf("Player.AddPhoneScore exception!!! num(%v) oper(%v)", num, oper)
				num = -this.PhoneScore
				this.PhoneScore = 0
			} else {
				this.PhoneScore += num
			}
		}

		this.SendDiffData()
	}
}

// 抽奖任务
func (this *Player) PhoneLotteryTask(taskId int32, num int64) {
	if WelfareMgrSington.GetPhoneLotteryStatus(this.Platform) == WelfareClose {
		if this.WelfData != nil && this.WelfData.PhoneLotteryTask != nil {
			this.WelfData.PhoneLotteryTask = make(map[int32]*model.TaskData)
		}
		return
	}
	if this.WelfData == nil {
		this.WelfData = model.NewWelfareData()
	}
	if this.WelfData.PhoneLotteryTask == nil {
		this.WelfData.PhoneLotteryTask = make(map[int32]*model.TaskData)
	}
	if this.WelfData.PhoneLotteryTask[taskId] == nil {
		this.WelfData.PhoneLotteryTask[taskId] = &model.TaskData{N: 0} // 初始化任务数据
	}
	switch taskId {
	case common.TaskTypePay:
		this.WelfData.PhoneLotteryTask[taskId].N += num
		if this.WelfData.PhoneLotteryTask[taskId].N/20 > 0 {
			count := this.WelfData.PhoneLotteryTask[taskId].N / 20
			this.addLotteryCount(int32(count))
			this.WelfData.PhoneLotteryTask[taskId].N = this.WelfData.PhoneLotteryTask[taskId].N % 20
			LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(this.SnId, this.Platform, "", 3, int(count), 4, 0))
		}

	case common.TaskTypeWinOrLose:
		this.WelfData.PhoneLotteryTask[taskId].N += num
		if this.WelfData.PhoneLotteryTask[taskId].N/200000000 > 0 {
			count := this.WelfData.PhoneLotteryTask[taskId].N / 200000000
			this.addLotteryCount(int32(count))
			this.WelfData.PhoneLotteryTask[taskId].N = this.WelfData.PhoneLotteryTask[taskId].N % 200000000
			LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(this.SnId, this.Platform, "", 3, int(count), 3, 0))
		}

	case common.TaskTypeTienlenCount:
		this.WelfData.PhoneLotteryTask[taskId].N += num
		if this.WelfData.PhoneLotteryTask[taskId].N/20 > 0 {
			count := this.WelfData.PhoneLotteryTask[taskId].N / 20
			this.addLotteryCount(int32(count))
			this.WelfData.PhoneLotteryTask[taskId].N = this.WelfData.PhoneLotteryTask[taskId].N % 20
			LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(this.SnId, this.Platform, "", 3, int(count), 2, 0))
		}
	case common.TaskTypeFirstLogin:
		this.addLotteryCount(5)
		LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(this.SnId, this.Platform, "", 3, 5, 1, 0))
	default:
		logger.Logger.Errorf("手机抽奖任务未找到对应的任务ID: %d", taskId)
		return
	}
}

func (this *Player) InviteTask(scoreType int32, gameId int32, n int64) {
	if this.InviteSnId == 0 {
		return
	}

	if this.WelfData == nil {
		this.WelfData = model.NewWelfareData()
	}
	if this.WelfData.Task == nil {
		this.WelfData.Task = make(map[int32]*model.TaskData)
	}

	switch scoreType {
	case common.InviteScoreTypeBind:
		SaveInviteScore(&model.InviteScore{
			Platform:   this.Platform,
			SnId:       this.SnId,
			InviteSnId: this.InviteSnId,
			Tp:         scoreType,
			Score:      5000,
			Ts:         time.Now().UnixNano(),
		})

	case common.InviteScoreTypeLogin:
		if this.WelfData.Task[common.TaskIDInviteFirstLogin] == nil {
			this.WelfData.Task[common.TaskIDInviteFirstLogin] = &model.TaskData{} // 初始化任务数据
		}
		if this.WelfData.Task[common.TaskIDInviteFirstLogin].Ts == 0 {
			this.WelfData.Task[common.TaskIDInviteFirstLogin].Ts = time.Now().Unix()
			SaveInviteScore(&model.InviteScore{
				Platform:   this.Platform,
				SnId:       this.SnId,
				InviteSnId: this.InviteSnId,
				Tp:         scoreType,
				Score:      1000,
				Ts:         time.Now().UnixNano(),
			})
		}

	case common.InviteScoreTypePlayTimes:
		if this.WelfData.Task[common.TaskIDInvitePlayGame] == nil {
			this.WelfData.Task[common.TaskIDInvitePlayGame] = &model.TaskData{} // 初始化任务数据
		}
		if this.WelfData.Task[common.TaskIDInvitePlayGame].Ts == 0 {
			this.WelfData.Task[common.TaskIDInvitePlayGame].Ts = time.Now().Unix()
			SaveInviteScore(&model.InviteScore{
				Platform:   this.Platform,
				SnId:       this.SnId,
				InviteSnId: this.InviteSnId,
				Tp:         scoreType,
				Score:      5000,
				Ts:         time.Now().UnixNano(),
			})
		}

	case common.InviteScoreTypeRecharge:
		if this.WelfData.Task[common.TaskIDInviteRecharge] == nil {
			this.WelfData.Task[common.TaskIDInviteRecharge] = &model.TaskData{} // 初始化任务数据
		}
		this.WelfData.Task[common.TaskIDInviteRecharge].N += n
		a := this.WelfData.Task[common.TaskIDInviteRecharge].N / 100
		this.WelfData.Task[common.TaskIDInviteRecharge].N %= 100
		SaveInviteScore(&model.InviteScore{
			Platform:   this.Platform,
			SnId:       this.SnId,
			InviteSnId: this.InviteSnId,
			Tp:         scoreType,
			Score:      a * 10000,
			Ts:         time.Now().UnixNano(),
		})

	case common.InviteScoreTypeGameTimes:
		score := 0
		switch {
		case common.IsTienLen(int(gameId)):
			score = 500
		case common.IsThirteen(int(gameId)):
			score = 300
		case common.IsSmallRocket(int(gameId)):
			score = 30
		case common.IsChess(int(gameId)):
			score = 100
		}
		SaveInviteScore(&model.InviteScore{
			Platform:   this.Platform,
			SnId:       this.SnId,
			InviteSnId: this.InviteSnId,
			Tp:         scoreType,
			Score:      int64(score),
			Ts:         time.Now().UnixNano(),
		})
	}
}

func (this *Player) ResetTaskN(tp int32) {
	if this.WelfData == nil || this.WelfData.Task == nil {
		return
	}

	for _, v := range srvdata.PBDB_TaskMgr.Datas.GetArr() {
		if v.GetTaskType() != tp {
			continue
		}
		data := this.WelfData.Task[v.GetId()]
		if data != nil {
			data.N = 0
		}
	}
}

func (this *Player) ResetTask(tp int32) {
	if this.WelfData == nil || this.WelfData.Task == nil {
		return
	}

	for _, v := range srvdata.PBDB_TaskMgr.Datas.GetArr() {
		if v.GetTaskType() != tp {
			continue
		}
		this.WelfData.Task[v.GetId()] = &model.TaskData{}
	}
}
