game_sync/gamesrv/fishing/playerdata_fishing.go

527 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

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

package fishing
import (
"fmt"
"mongo.games.com/game/common"
"mongo.games.com/game/gamerule/fishing"
"mongo.games.com/game/gamesrv/base"
"mongo.games.com/game/model"
"mongo.games.com/game/proto"
server_proto "mongo.games.com/game/protocol/server"
"mongo.games.com/game/srvdata"
"mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/task"
"os"
"strconv"
"time"
)
type FishingPlayerEvent struct {
FishId int32 // 唯一标识 PolicyId*1000000 + int32(value.GetId())*100 + int32(index+1)
Event int32 // 鱼触发的事件id
Power int32 // 炮台倍率
Ts int64 // 时间戳
DropCoin int32 // 鱼掉落金币
ExtFishId []int32 // 相关鱼的鱼标识
}
type FishingPlayerData struct {
*base.Player
scene *base.Scene // 玩家当前所在场景
LastFireTime time.Time // 用来计时3分钟不在线踢出房间
power int32 // 炮台倍率
CoinCache int64 // 实时余额
bullet map[int32]*Bullet // 子弹
BulletLimit [BULLETLIMIT]int64 // 检测开枪频率过大
fishEvent map[string]*FishingPlayerEvent // 事件标识:事件
LostCoin int64 // 进场之后消耗的金币(子弹消耗)
LostCoinCache int64 // 保存游戏记录时的消耗金币,保存一次刷新一次,用来计算上次保存记录后消耗了多少金币
AgentParam int32 // 机器人该字段表示代理玩家的id玩家该字段表示其代理的其中一个机器人的id
RobotSnIds []int32 // 真实玩家绑定的机器人数组
AutoFishing int32 // 自动标记
SelTarget int32 // 瞄准数据?
TargetFish int32 // 瞄准的鱼标识?
FireRate int32 // 开炮频率
taxCoin float64 // 开炮税收
sTaxCoin float64 // 开炮税收(保存游戏记录时清零)
enterTime time.Time // 玩家入场时间
SelVip int32 // 玩家选择的vip炮等级
powerType int32 // 玩家炮台的类型
FreePowerNum int32 // 免费炮台炮弹的数量
winCoin int64 // 入场后总赢分
realOdds int // 玩家的实际赔率?
logBulletHitNums int32 // 命中计数,保存记录时清零
logFishCount map[int64]*model.FishCoinNum // key:鱼id和子弹倍率游戏记录
EnterCoin int64 // 进场金币 统计使用
lockFishCount map[int32]int32 // 鱼id对应打死的数量天天捕鱼
jackpotCoin float64 // 用来收集不足1的金币天天捕鱼
Prana float64 // 蓄能能量(天天捕鱼)
PranaPercent int32 // 蓄能能量百分比(天天捕鱼)
MaxCoin int64 // 游戏场最大金币(天天捕鱼)
MinCoin int64 // 游戏场最少金币(天天捕鱼)
ExtraCoin int64 // 除捕鱼外额外获得的金币(天天捕鱼)
TestHitNum int64 // 测试碰撞次数(天天捕鱼)
SkillCd map[int32]int64 //技能CD
SkillGCD map[int32]int64 //技能公共CD
//SkillMutex sync.Mutex
}
/*
更新免费炮台相关状态
*/
func (this *FishingPlayerData) UpdateFreePowerState() {
this.powerType = FreePowerType
this.FreePowerNum = 100
}
/*
更新成普通炮台相关状态
*/
func (this *FishingPlayerData) UpdateNormalPowerState() {
this.powerType = NormalPowerType
this.FreePowerNum = 0
}
/*
更新成钻头炮台相关状态
*/
func (this *FishingPlayerData) UpdateBitPowerState() {
this.powerType = BitPowerType
}
func (this *FishingPlayerData) MakeLogKey(fishTemplateId, power int32) int64 {
return common.MakeI64(fishTemplateId, power)
}
func (this *FishingPlayerData) SplitLogKey(key int64) (int32, int32) {
return common.LowI32(key), common.HighI32(key)
}
func (this *FishingPlayerData) init(s *base.Scene) {
//this.Player.extraData = this
this.Player.SetExtraData(this)
this.LostCoin = 0
this.LostCoinCache = 0
this.power = s.GetDBGameFree().GetIntuseCannonMin()
this.AgentParam = 0
this.bullet = make(map[int32]*Bullet)
this.BulletLimit = [BULLETLIMIT]int64{}
this.fishEvent = make(map[string]*FishingPlayerEvent)
this.logBulletHitNums = 0
this.lockFishCount = make(map[int32]int32)
this.logFishCount = make(map[int64]*model.FishCoinNum)
this.jackpotCoin = 0.0
this.TestHitNum = 0
this.scene = s
this.SkillGCD = make(map[int32]int64)
this.SkillCd = make(map[int32]int64)
this.LastFireTime = time.Now()
if this.GDatas == nil {
this.GDatas = make(map[string]*model.PlayerGameInfo)
}
if !s.GetTesting() && !this.IsRob {
key := s.KeyGamefreeId
var pgd *model.PlayerGameInfo
if data, exist := this.GDatas[key]; !exist {
pgd = new(model.PlayerGameInfo)
this.GDatas[key] = pgd
} else {
pgd = data
}
if pgd != nil {
//参数确保
for i := len(pgd.Data); i < GDATAS_HPFISHING_MAX; i++ {
pgd.Data = append(pgd.Data, 0)
}
this.Prana = float64(pgd.Data[GDATAS_HPFISHING_PRANA])
//this.SelVip = int32(pgd.Data[GDATAS_FISHING_SELVIP])
}
////////////////////////
var npgd *model.PlayerGameInfo
if ndata, exist := this.GDatas[s.KeyGameId]; !exist {
npgd = new(model.PlayerGameInfo)
this.GDatas[s.KeyGameId] = npgd
} else {
npgd = ndata
}
if npgd != nil {
//参数确保
for i := len(npgd.Data); i < GDATAS_HPFISHING_MAX; i++ {
npgd.Data = append(npgd.Data, 0)
}
this.SelVip = int32(npgd.Data[GDATAS_FISHING_SELVIP])
}
}
this.Clean()
}
func (this *FishingPlayerData) SetSelVip(keyGameId string) {
if pgd, ok := this.GDatas[keyGameId]; ok {
pgd.Data[GDATAS_FISHING_SELVIP] = int64(this.SelVip)
}
}
func (this *FishingPlayerData) Clean() {
this.bullet = make(map[int32]*Bullet)
this.BulletLimit = [BULLETLIMIT]int64{}
this.fishEvent = make(map[string]*FishingPlayerEvent)
this.logBulletHitNums = 0
this.bullet = make(map[int32]*Bullet)
this.logFishCount = make(map[int64]*model.FishCoinNum)
}
func (this *FishingPlayerData) CoinCheck(power int32) bool {
return this.CoinCache >= int64(power)
}
func (this *FishingPlayerData) CurrentCoin() int64 {
return this.CoinCache
}
func (this *FishingPlayerData) GetTodayGameData(gameId string) *model.PlayerGameStatics {
if this.TodayGameData == nil {
this.TodayGameData = model.NewPlayerGameCtrlData()
}
if this.TodayGameData.CtrlData == nil {
this.TodayGameData.CtrlData = make(map[string]*model.PlayerGameStatics)
}
if _, ok := this.TodayGameData.CtrlData[gameId]; !ok {
this.TodayGameData.CtrlData[gameId] = model.NewPlayerGameStatics()
}
return this.TodayGameData.CtrlData[gameId]
}
/*
设置当天数据
*/
func (this *FishingPlayerData) SetTodayGameDate(gameId string, playerGameStatics *model.PlayerGameStatics) {
this.TodayGameData.CtrlData[gameId] = playerGameStatics
}
/*
获取昨日得当天数据集合
*/
func (this *FishingPlayerData) GetYestDayGameData(gameId string) *model.PlayerGameStatics {
if this.YesterdayGameData == nil {
this.YesterdayGameData = &model.PlayerGameCtrlData{}
}
if this.YesterdayGameData.CtrlData == nil {
this.YesterdayGameData.CtrlData = make(map[string]*model.PlayerGameStatics)
}
if _, ok := this.YesterdayGameData.CtrlData[gameId]; !ok {
this.YesterdayGameData.CtrlData[gameId] = model.NewPlayerGameStatics()
}
return this.YesterdayGameData.CtrlData[gameId]
}
func (this *FishingPlayerData) SaveDetailedLog(s *base.Scene) {
if len(this.logFishCount) == 0 {
return
}
if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
if sceneEx.GetTesting() && this.IsRob {
this.logFishCount = make(map[int64]*model.FishCoinNum)
return
}
totalin := int64(0)
totalout := int64(0)
var fd model.FishDetiel
logBulletCount := make(map[int32]int32)
fcn := make([]model.FishCoinNum, 0)
for k, v := range this.logFishCount {
FishTemplateId, power := this.SplitLogKey(k)
fcn = append(fcn, model.FishCoinNum{ID: FishTemplateId, Power: power, Num: v.Num, Coin: v.Coin, HitNum: v.HitNum})
totalout += int64(v.Coin)
logBulletCount[power] += v.HitNum
}
fd.HitInfo = &fcn
bt := make([]model.BulletLevelTimes, 0)
for k, v := range logBulletCount {
bt = append(bt, model.BulletLevelTimes{Level: k, Times: v})
totalin += int64(k * v)
}
fd.BulletInfo = &bt
fp := &model.FishPlayerData{
UserId: this.SnId,
UserIcon: this.Head,
TotalIn: totalin,
TotalOut: totalout,
CurrCoin: this.CoinCache,
}
// 捕鱼不需要个人信息里的战绩
//win := totalout - totalin
//var isWin int32
//if win > 0 {
// isWin = 1
//} else if win < 0 {
// isWin = -1
//}
//sceneEx.SaveFriendRecord(this.SnId, isWin)
fd.PlayData = fp
info, err := model.MarshalGameNoteByFISH(&fd)
if err == nil {
logid, _ := model.AutoIncGameLogId()
sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{
LogId: logid,
Platform: this.Platform,
Snid: this.SnId,
PlayerName: this.Name,
Channel: this.Channel,
ChannelId: this.ChannelId,
TotalIn: totalin,
TotalOut: totalout,
TaxCoin: int64(this.sTaxCoin),
BetAmount: totalin,
WinAmountNoAnyTax: totalout,
IsFirstGame: sceneEx.IsPlayerFirst(this.Player),
})
sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{
LogId: logid,
Detail: info,
})
}
pack := &server_proto.GWFishRecord{
GameFreeId: proto.Int32(sceneEx.GetDBGameFree().GetId()),
SnId: proto.Int32(this.SnId),
}
for _, v := range this.logFishCount {
fishRecord := &server_proto.FishRecord{
FishId: proto.Int32(v.ID),
Count: proto.Int32(v.Num),
}
pack.FishRecords = append(pack.FishRecords, fishRecord)
}
if len(pack.FishRecords) > 0 {
this.SendToWorld(int(server_proto.SSPacketID_PACKET_GW_FISHRECORD), pack)
}
diffLostCoin := this.LostCoin - this.LostCoinCache
this.LostCoinCache = this.LostCoin
gain := totalout - totalin
this.Statics(s.KeyGameId, s.KeyGamefreeId, gain, true)
if diffLostCoin > 0 {
playerBet := &server_proto.PlayerData{
SnId: proto.Int32(this.SnId),
Bet: proto.Int64(totalin),
Gain: proto.Int64(gain),
Tax: proto.Int64(int64(this.sTaxCoin)),
Coin: proto.Int64(this.Coin),
GameCoinTs: proto.Int64(this.GameCoinTs),
}
gwPlayerData := &server_proto.GWPlayerData{
SceneId: sceneEx.SceneId,
GameFreeId: proto.Int32(sceneEx.GetDBGameFree().GetId()),
}
gwPlayerData.Datas = append(gwPlayerData.Datas, playerBet)
proto.SetDefaults(gwPlayerData)
sceneEx.SendToWorld(int(server_proto.SSPacketID_PACKET_GW_PLAYERDATA), gwPlayerData)
}
}
this.sTaxCoin = 0
this.logBulletHitNums = 0
this.logFishCount = make(map[int64]*model.FishCoinNum)
}
func (this *FishingPlayerData) SetMaxCoin() {
if this.CoinCache > this.MaxCoin {
this.MaxCoin = this.CoinCache
}
}
func (this *FishingPlayerData) SetMinCoin() {
if this.CoinCache < this.MinCoin || this.MinCoin == 0 {
this.MinCoin = this.CoinCache
}
}
func (this *FishingPlayerData) SaveFishingLog(curCoin int64, gameid string) {
data := this.GDatas[gameid]
log := fmt.Sprintf("%v,%v,%v,%v,%v\n", this.CurrentCoin(), data.Statics.TotalIn, data.Statics.TotalOut, curCoin, base.GetCoinPoolMgr().GetTax())
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
fileName := fmt.Sprintf("fishdata-%v.csv", this.SnId)
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm)
defer file.Close()
if err != nil {
file, err = os.Create(fileName)
if err != nil {
return err
}
}
file.WriteString(log)
return nil
}), nil, "SaveFishingLog").StartByFixExecutor("SaveFishingLog")
}
// NewStatics .b
func (this *FishingPlayerData) NewStatics(betCoin, gain int64) {
if this.scene == nil || this.scene.GetTesting() || this.IsRob { //测试场和机器人不统计
return
}
if betCoin == 0 && gain == 0 {
return
}
// start 如果当前处于免费炮的情况,NewStatics 记录消费为0
if this.powerType == FreePowerType {
betCoin = 0
}
// end
//黑白名单不参与投入产出统计,影响自己和他人体验
if this.WBLevel != 0 || this.WhiteFlag != 0 || this.GMLevel > 0 {
return
}
fishlogger.Tracef("============snid=%v betCoin=%v gain=%v ", this.SnId, betCoin, gain)
keyGlobal := fmt.Sprintf("%v_%v", this.scene.GetPlatform(), this.scene.GetGameFreeId())
if base.SysProfitCoinMgr.SysPfCoin != nil {
if base.SysProfitCoinMgr.SysPfCoin.ProfitCoin == nil {
base.SysProfitCoinMgr.SysPfCoin.ProfitCoin = make(map[string]*model.SysCoin)
}
var syscoin *model.SysCoin
if data, exist := base.SysProfitCoinMgr.SysPfCoin.ProfitCoin[keyGlobal]; !exist {
syscoin = new(model.SysCoin)
base.SysProfitCoinMgr.SysPfCoin.ProfitCoin[keyGlobal] = syscoin
} else {
syscoin = data
}
syscoin.PlaysBet += betCoin
syscoin.SysPushCoin += gain
fishlogger.Tracef("============SysProfitCoinMgr key=%v PlaysBet:= %v SysPushCoin= %v ", keyGlobal, syscoin.PlaysBet, syscoin.SysPushCoin)
}
keyPlayer := strconv.Itoa(int(this.scene.GetGameFreeId()))
var pgd *model.PlayerGameInfo
if d, exist := this.GDatas[keyPlayer]; exist {
FishGDataLen(len(d.Data), d)
pgd = d
} else {
pgd = &model.PlayerGameInfo{
Data: make([]int64, GDATAS_HPFISHING_MAX, GDATAS_HPFISHING_MAX),
}
this.GDatas[keyPlayer] = pgd
}
low := pgd.Data[GDATAS_HPFISHING_ALLBET]
high := pgd.Data[GDATAS_HPFISHING_ALLBET64]
allBet := common.MakeI64(int32(low), int32(high)) + betCoin
pgd.Data[GDATAS_HPFISHING_ALLBET], pgd.Data[GDATAS_HPFISHING_ALLBET64] = common.LowAndHighI64(allBet)
pgd.Data[GDATAS_HPFISHING_CHANGEBET] += int64(gain)
fishlogger.Tracef("============snid=%v total fish betCoin:= %v gain=%v ", this.SnId, allBet,
pgd.Data[GDATAS_HPFISHING_CHANGEBET])
}
// GetAllBet .
func (this *FishingPlayerData) GetAllBet(key string) int64 {
ret := int64(1)
if d, exist := this.GDatas[key]; exist {
FishGDataLen(len(d.Data), d)
ret = common.MakeI64(int32(d.Data[GDATAS_HPFISHING_ALLBET]), int32(d.Data[GDATAS_HPFISHING_ALLBET64]))
}
return ret
}
// GetAllChangeBet .
func (this *FishingPlayerData) GetAllChangeBet(key string) int64 {
ret := int64(0)
if d, exist := this.GDatas[key]; exist {
FishGDataLen(len(d.Data), d)
ret = int64(d.Data[GDATAS_HPFISHING_CHANGEBET])
}
return ret
}
// 计算个人赔率和个人限制系数
func (this *FishingPlayerData) GetPlayerOdds(gameid string, ctroRate int32, fishlevel int32) (float64, float64) {
if data, ok := this.GDatas[gameid]; ok {
//总产出初始值 = 100*1-调节频率)*100 (分) 初级场
//总产出初始值 = 1000*1-调节频率)*100 (分) 中级场
//总产出初始值 = 10000*1-调节频率)*100 (分) 高级场
//总投入初始值 = 100*100 (分) 初级场
//总投入初始值 = 1000*100 (分) 中级场
//总投入初始值 = 10000*100 (分) 高级场
initBaseValue := int64(10000) //1万分
if fishlevel == 2 {
initBaseValue = 100000
} else if fishlevel == 3 {
initBaseValue = 1000000
}
totalInValue := initBaseValue + data.Statics.TotalIn
totalOutValue := initBaseValue*(10000-int64(ctroRate))/10000 + data.Statics.TotalOut
//个人限制系数
ratio := 1.0
if fishlevel == 1 && totalOutValue-totalInValue >= 20000 {
ratio = 0.5
} else if fishlevel == 2 && totalOutValue-totalInValue >= 100000 {
ratio = 0.5
} else if fishlevel == 3 && totalOutValue-totalInValue >= 500000 {
ratio = 0.5
}
return float64(totalOutValue) / float64(totalInValue), ratio
} else {
fishlogger.Errorf("player.GDatas[%v] is %v", gameid, this.GDatas[gameid])
return 0, 0
}
}
var FishGDataLen = func(flen int, pgd *model.PlayerGameInfo) {
if flen < GDATAS_HPFISHING_MAX {
for i := flen; i < GDATAS_HPFISHING_MAX; i++ {
pgd.Data = append(pgd.Data, 0)
}
}
}
// 增加技能CD
func (this *FishingPlayerData) AddSkillCD(skillId, skillType, cdTime, gcdTime int32) {
/* this.SkillMutex.Lock()
defer this.SkillMutex.Unlock()*/
this.SkillCd[skillId] = time.Now().UnixNano()/int64(time.Millisecond) + int64(cdTime*1000)
this.SkillGCD[skillType] = time.Now().UnixNano()/int64(time.Millisecond) + int64(gcdTime*1000)
}
// 判断技能在不在CD中
func (this *FishingPlayerData) GetSkillCD(skillId, skillType int32) bool {
_, exists := this.SkillCd[skillId]
if exists {
return false
}
_, exists = this.SkillGCD[skillType]
if exists {
return false
}
return true
}
// 玩家升级解锁炮倍
func (this *FishingPlayerData) PlayerEvent(eventType, id int64) {
switch eventType {
case fishing.Event_Player_UpLevel:
//获取解锁的炮倍
power := srvdata.PlayerExpMgr.GetUnPower(int32(id))
if power != 0 {
this.UnPlayerPowerEx(int64(power))
}
break
case fishing.Event_Player_UnMaxPower:
//id 直接解锁炮倍 后期用
this.UnPlayerPowerEx(id)
break
case fishing.Event_Player_UnPowerList:
//id 解锁的炮台ID
this.UnPlayerPowerListEx(int32(id))
break
default:
fishlogger.Errorf("未处理的玩家事件 eventType = %v", eventType)
break
}
}