go_dreamfactory/modules/arena/modelarena.go
2024-02-06 15:27:12 +08:00

624 lines
18 KiB
Go

package arena
import (
"context"
"fmt"
"go_dreamfactory/comm"
"go_dreamfactory/lego/core"
"go_dreamfactory/lego/sys/log"
"go_dreamfactory/lego/sys/mgo"
"go_dreamfactory/modules"
"go_dreamfactory/pb"
"go_dreamfactory/sys/configure"
cfg "go_dreamfactory/sys/configure/structs"
"go_dreamfactory/sys/db"
"math"
"math/rand"
"time"
"go_dreamfactory/utils"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/bsonx"
)
// /竞技场 数据组件
type modelArena struct {
modules.MCompModel
module *Arena
}
// 组件初始化接口
func (this *modelArena) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) {
this.TableName = comm.TableArena
this.MCompModel.Init(service, module, comp, opt)
this.module = module.(*Arena)
//创建uid索引
if _, err = this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{
Keys: bsonx.Doc{
{Key: "uid", Value: bsonx.Int32(1)},
},
}); err != nil {
return
}
_, err = this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{
Keys: bson.M{"loc": "2dsphere"},
})
return
}
//是否在维护中
func (this *modelArena) isInMaintenance() (ok bool) {
var (
opentime time.Time
totalduration time.Duration
lefttime time.Duration
)
opentime = this.module.service.GetOpentime()
totalduration = configure.Now().Sub(opentime)
lefttime = totalduration % (time.Hour * 24 * 7 * time.Duration(this.module.ModuleTools.GetGlobalConf().PvpEndtime))
if lefttime < time.Hour*time.Duration(this.module.ModuleTools.GetGlobalConf().PvpMaintenancetime) {
return true
}
return false
}
//获取赛季结算时间
func (this *modelArena) settlementTime() (endtime time.Time) {
var (
opentime time.Time
totalduration time.Duration
lefttime time.Duration
)
opentime = this.module.service.GetOpentime()
totalduration = configure.Now().Sub(opentime)
lefttime = totalduration % (time.Hour * 24 * 7 * time.Duration(this.module.ModuleTools.GetGlobalConf().PvpEndtime))
endtime = configure.Now().Add(time.Hour*24*7*time.Duration(this.module.ModuleTools.GetGlobalConf().PvpEndtime) - lefttime)
return
}
// 查询用户装备数据
func (this *modelArena) queryPlayerInfo(uId string) (result *pb.DBArenaUser, err error) {
result = &pb.DBArenaUser{}
if err = this.Get(uId, result); err != nil && err != mgo.MongodbNil {
this.module.Errorln(err)
return
}
return
}
// 查询用户装备数据
func (this *modelArena) queryPlayers(uIds []string) (result []*pb.DBArenaUser, err error) {
result = make([]*pb.DBArenaUser, 0)
if _, err = this.GetByUids(uIds, &result); err != nil && err != mgo.MongodbNil {
this.module.Errorln(err)
return
}
return
}
// 查询用户装备数据
func (this *modelArena) queryArenaPlayer(uId string) (result *pb.ArenaPlayer, err error) {
temp := &pb.DBArenaUser{}
if err = this.Get(uId, temp); err != nil {
this.module.Errorln(err)
return
}
result = &pb.ArenaPlayer{
Uinfo: temp.Uinfo,
Dan: temp.Dan,
Integral: temp.Integral,
Defend: temp.Defend,
Isai: false,
}
return
}
// 查询用户英雄数据
func (this *modelArena) queryUserHeros(uid string, heroids []string) (results []*pb.DBHero, err error) {
var (
model *db.DBModel
ids []string
resultstemp []*pb.DBHero
)
if model, err = this.module.GetDBModelByUid(uid, comm.TableHero); err != nil {
this.module.Errorln(err)
return
}
for _, v := range heroids {
if v != "" {
ids = append(ids, v)
}
}
resultstemp = make([]*pb.DBHero, 0)
if err = model.GetListObjs(uid, ids, &resultstemp); err != nil {
this.module.Errorln(err)
return
}
results = make([]*pb.DBHero, len(heroids))
for i1, v1 := range resultstemp {
for i2, _ := range results {
if i1 == i2 {
results[i2] = v1
}
}
}
return
}
// /保存用户竞技场信息
func (this *modelArena) updateArenaUserInfo(info *pb.DBArenaUser) (err error) {
var (
dan int32
)
if info.Integral < 0 {
info.Integral = 0
}
if dan, err = this.computedan(info.Integral); err != nil {
return
}
info.Dan = dan
this.Change(info.Uinfo.Uid, map[string]interface{}{
"integral": info.Integral,
"dan": dan,
"rank": info.Rank,
"buynum": info.Buynum,
"lastrtickettime": info.Lastrtickettime,
"attack": info.Attack,
"defend": info.Defend,
"streak": info.Streak,
"record": info.Record,
"attackwinuum": info.Attackwinuum,
"attacktotaluum": info.Attacktotaluum,
"defendwinuum": info.Defendwinuum,
"defendtotaluum": info.Defendtotaluum,
"loc": []float64{float64(dan), float64(rand.Int31n(100)) / 1000.0},
"isdef": info.Isdef,
"uinfo": info.Uinfo,
"dan2": info.Dan2,
"lastweektime": info.Lastweektime,
"settlementtime": info.Settlementtime,
"tasks": info.Tasks,
"danaward": info.Danaward,
"maxdan": info.Maxdan,
"weekaward": info.Weekaward,
"prededuction": info.Prededuction,
})
return
}
func (this *modelArena) modifyIntegral(uid string, integral int32) (err error) {
var (
dan int32
player *pb.ArenaPlayer
)
if dan, err = this.computedan(integral); err != nil {
return
}
player = &pb.ArenaPlayer{Uinfo: &pb.BaseUserInfo{Uid: uid}, Integral: integral}
if err = this.module.modelRank.updateArenaRank(player); err != nil {
this.module.Errorln(err)
return
}
this.Change(uid, map[string]interface{}{
"integral": integral,
"dan": dan,
"rank": player.Rank,
})
return
}
func (this *modelArena) computedan(integral int32) (dan int32, err error) {
var (
active *cfg.GameArenaActiveRewardData
)
if active, err = this.module.configure.getActiveReward(integral); err != nil {
this.module.Errorln(err)
return
}
dan = active.LvId
return
}
// 匹配机器人
func (this *modelArena) matcheAI(dan, num int32) (results []*pb.ArenaPlayer, err error) {
var (
active *cfg.GameArenaActiveRewardData
ais []*cfg.GameArenaRobotData
formats []*cfg.GameMonsterFormatData
robots []*cfg.GameRobotData
rank []int32
targets []int32
)
if active, err = this.module.configure.getActiveRewardById(dan); err != nil {
this.module.Errorln(err)
return
}
if ais, err = this.module.configure.getArenaRobot(dan); err != nil {
this.module.Errorln(err)
return
}
rank = make([]int32, len(ais))
for i, v := range ais {
rank[i] = v.Weight
}
targets = make([]int32, num)
for i := 0; i < int(num); i++ {
index := comm.GetRandW(rank)
targets[i] = index
}
results = make([]*pb.ArenaPlayer, num)
if robots, err = this.module.ModuleTools.RandRobotConfig(int32(len(targets))); err != nil {
return
}
for i, v := range targets {
aiconf := ais[v]
if formats, err = this.module.configure.getMonsterFormat(aiconf.MonsterformatId); err != nil {
this.module.Errorln(err)
return
}
results[i] = &pb.ArenaPlayer{
Uinfo: comm.GetRobotBaseInfo(robots[i]),
Dan: dan,
Integral: int32(rand.Intn(int(active.ScoreUp)-int(active.ScoreLow))) + active.ScoreLow,
Isai: true,
Mformatid: aiconf.MonsterformatId,
Defend: &pb.DBPlayerBattleFormt{
Leadpos: 0,
Formt: make([]*pb.DBHero, len(formats)),
},
}
for i1, v1 := range formats {
if v1 == nil {
results[i].Defend.Formt[i1] = nil
} else {
if v1.CaptainId == 1 {
results[i].Defend.Leadpos = int32(i1)
}
// if monst, err = this.module.configure.getMonster(v1.Monster); err != nil {
// this.module.Errorln(err)
// }
hero := &pb.DBHero{}
if hero = this.module.ModuleHero.CreateMonster(fmt.Sprintf("%d", v1.Heroid), v1.Star, v1.Lv); hero == nil {
err = fmt.Errorf("CreateMonster 失败")
return
}
hero.Property[cfg.GamePropertyType_Base_MaxHp_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_MaxHp_Base]) * v1.Hppro)
hero.Property[cfg.GamePropertyType_Base_Atk_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_Atk_Base]) * v1.Atkpro)
hero.Property[cfg.GamePropertyType_Base_Def_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_Def_Base]) * v1.Defpro)
hero.Suits = make([]*pb.DB_EquipmentSuit, 0)
for _, v := range v1.Equip {
hero.Suits = append(hero.Suits, &pb.DB_EquipmentSuit{
Suitid: v,
Effect: true,
})
}
results[i].Defend.Formt[i1] = hero
}
}
}
return
}
// 获取目标去陪数据
func (this *modelArena) matchePlayer(uid string, group, dan, num int32) (results []*pb.ArenaPlayer, err error) {
var (
cursor *mongo.Cursor
)
results = make([]*pb.ArenaPlayer, 0)
port := []float64{float64(dan), float64(rand.Int31n(100)) / 1000.0}
if cursor, err = this.DBModel.DB.Find(comm.TableArena, bson.M{
"isdef": true,
"uid": bson.M{"$ne": uid},
"uinfo.group": group,
"dan": dan,
"loc": bson.M{
"$near": bson.M{
"$geometry": bson.M{"type": "Point", "coordinates": port},
"$maxDistance": 100000,
},
},
}, options.Find().SetSkip(0).SetLimit(int64(num))); err != nil {
this.module.Errorln(err)
return
} else {
for cursor.Next(context.Background()) {
temp := &pb.DBArenaUser{}
if err = cursor.Decode(temp); err != nil {
this.module.Errorln(err)
return
}
results = append(results, &pb.ArenaPlayer{
Uinfo: temp.Uinfo,
Dan: temp.Dan,
Integral: temp.Integral,
Defend: temp.Defend,
})
}
}
return
}
func (this *modelArena) getAI(mformatId int32) (ai *pb.ArenaPlayer, err error) {
var (
robots []*cfg.GameRobotData
formats []*cfg.GameMonsterFormatData
)
if robots, err = this.module.ModuleTools.RandRobotConfig(1); err != nil {
return
}
if formats, err = this.module.configure.getMonsterFormat(mformatId); err != nil {
this.module.Errorln(err)
return
}
ai = &pb.ArenaPlayer{
Uinfo: comm.GetRobotBaseInfo(robots[0]),
Isai: true,
Mformatid: mformatId,
Defend: &pb.DBPlayerBattleFormt{
Leadpos: 0,
Formt: make([]*pb.DBHero, len(formats)),
},
}
for i1, v1 := range formats {
if v1 == nil {
ai.Defend.Formt[i1] = nil
} else {
hero := &pb.DBHero{}
if hero = this.module.ModuleHero.CreateMonster(fmt.Sprintf("%d", v1.Heroid), v1.Star, v1.Lv); hero == nil {
err = fmt.Errorf("CreateMonster 失败")
return
}
hero.Property[cfg.GamePropertyType_Base_MaxHp_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_MaxHp_Base]) * v1.Hppro)
hero.Property[cfg.GamePropertyType_Base_Atk_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_Atk_Base]) * v1.Atkpro)
hero.Property[cfg.GamePropertyType_Base_Def_Base] = int32(float32(hero.Property[cfg.GamePropertyType_Base_Def_Base]) * v1.Defpro)
hero.Suits = make([]*pb.DB_EquipmentSuit, 0)
for _, v := range v1.Equip {
hero.Suits = append(hero.Suits, &pb.DB_EquipmentSuit{
Suitid: v,
Effect: true,
})
}
ai.Defend.Formt[i1] = hero
}
}
return
}
// 积分计算
func (this *modelArena) integralCompute(red, bule *pb.ArenaPlayer, iswin bool) {
var (
redactive *cfg.GameArenaActiveRewardData
buleactive *cfg.GameArenaActiveRewardData
err error
)
if redactive, err = this.module.configure.getActiveRewardById(red.Dan); err != nil {
this.module.Errorln(err)
return
}
if buleactive, err = this.module.configure.getActiveRewardById(bule.Dan); err != nil {
this.module.Errorln(err)
return
}
if iswin {
red.Changeintegral = int32(float64(redactive.KValue) * float64(1-1/float32(1+math.Pow(10, float64(float64(bule.Integral-red.Integral)/400)))))
bule.Changeintegral = int32(float64(buleactive.KValue) * float64(0-1/float64(1+math.Pow(10, float64(float64(red.Integral-bule.Integral))/400))))
} else {
red.Changeintegral = int32(float64(redactive.KValue) * float64(0-1/float64(1+math.Pow(10, float64(float64(bule.Integral-red.Integral)/400)))))
bule.Changeintegral = int32(float64(redactive.KValue) * float64(1-1/float64(1+math.Pow(10, float64(float64(red.Integral-bule.Integral)/400)))))
}
if red.Integral+red.Changeintegral < 0 {
red.Changeintegral = -red.Integral
red.Integral = 0
} else {
red.Integral = red.Integral + red.Changeintegral
}
if bule.Integral+bule.Changeintegral < 0 {
bule.Changeintegral = -bule.Integral
bule.Integral = 0
} else {
bule.Integral = bule.Integral + bule.Changeintegral
}
}
func (this *modelArena) recoverTicket(session comm.IUserSession, info *pb.DBArenaUser) {
var (
duration time.Duration
ticketitem *cfg.Gameatn
ticket int32
ticketNum int32
)
if ticketitem = this.module.ModuleTools.GetGlobalConf().ArenaTicketCos; ticketitem == nil {
this.module.Error("竞技场配置未找到!", log.Field{Key: "key", Value: "ArenaTicketCos"})
return
}
global := this.module.ModuleTools.GetGlobalConf()
maxTick := global.ArenaTicketMax
// 竞技场最大上限
maxTick += this.module.privilege.GetCountByPrivilegeId(session.GetUserId(), comm.PrivilegeType10) // 特权
ticket = int32(this.module.ModuleItems.QueryItemAmount(info.Uinfo.Uid, ticketitem.T))
if ticket < maxTick && info.Lastrtickettime > 0 {
duration = configure.Now().Sub(time.Unix(info.Lastrtickettime, 0))
ticketNum = int32(math.Floor(duration.Minutes() / float64(global.ArenaTicketRecoveryTime)))
if ticketNum > 0 {
if ticketNum+ticket > global.ArenaTicketMax {
ticketNum = global.ArenaTicketMax - ticket
}
this.module.DispenseRes(session, []*cfg.Gameatn{{A: ticketitem.A, T: ticketitem.T, N: ticketNum}}, true)
info.Lastrtickettime = time.Unix(info.Lastrtickettime, 0).Add(time.Duration(ticketNum) * time.Minute).Unix()
}
}
}
// 更新埋点数据到db中
func (this *modelArena) getpandataModel() (model *arenaModel, err error) {
var m *db.DBModel
if !db.IsCross() {
if m, err = this.module.GetCrossDBModel(this.TableName); err != nil {
return
}
model = &arenaModel{module: this.module, model: m}
} else {
model = &arenaModel{module: this.module, model: this.DBModel}
}
return
}
//周结算
func (this *modelArena) weeksettlement(session comm.IUserSession, info *pb.DBArenaUser) {
var (
conf *cfg.GameArenaActiveRewardData
confs []*cfg.GameArenaActiveKingData
totalnum int64
rank int32
reward []*cfg.Gameatn
atno []*pb.UserAtno
errdata *pb.ErrorData
ok bool
err error
)
if utils.IsSameWeek(info.Lastweektime) { //跨周
if conf, err = this.module.configure.getMaxDanConf(); err != nil {
return
}
if info.Dan == conf.LvId { //最高段位
if totalnum, err = this.module.modelRank.queryRankByScoreArea(conf.ScoreLow, -1); err != nil {
this.module.Errorln(err)
return
}
if info.Rank < int32(totalnum) { //存在于王者段位中
if confs, err = this.module.configure.getGameActiveKing(); err != nil {
this.module.Errorln(err)
return
}
for _, conf := range confs {
rank += int32(math.Floor(float64(conf.Place) * float64(totalnum) / float64(1000)))
if rank <= info.Dan {
reward = conf.RewardWeek
info.Dan2 = conf.LvId
ok = true
break
}
}
}
}
if !ok {
if conf, err = this.module.configure.getActiveRewardById(info.Dan); err != nil {
return
}
reward = conf.ExReward
info.Dan2 = 0
}
if errdata, atno = this.module.DispenseAtno(session, reward, true); errdata != nil {
this.module.Errorln(errdata)
return
}
info.Weekaward = append(info.Weekaward, &pb.DBWeekAward{
Dan: info.Dan,
Dan2: info.Dan2,
Award: atno,
})
session.SendMsg(string(this.module.GetType()), "settlementreward", &pb.ArenaSettlementRewardPush{Stype: 1, Award: atno})
}
}
// 比赛结算
func (this *modelArena) raceSettlement(session comm.IUserSession, info *pb.DBArenaUser) {
var (
conf *cfg.GameArenaActiveRewardData
err error
)
if configure.Now().After(time.Unix(info.Settlementtime, 0)) { //结算赛季
if conf, err = this.module.configure.getActiveRewardById(info.Dan); err != nil {
return
}
if conf.ScoreReturn >= 0 {
info.Integral = conf.ScoreReturn
info.Settlementtime = this.settlementTime().Unix()
}
}
return
}
// 埋点专属模型 会封装特殊的数据转换接口
type arenaModel struct {
module *Arena
model *db.DBModel
}
// 查询用户装备数据
func (this *arenaModel) queryPlayerInfo(uId string) (result *pb.DBArenaUser, err error) {
result = &pb.DBArenaUser{}
if err = this.model.Get(uId, result); err != nil && err != mgo.MongodbNil {
this.module.Errorln(err)
return
}
return
}
func (this *arenaModel) reddot(session comm.IUserSession) (info *pb.DBArenaUser, ticket int32, activated bool) {
var (
err error
)
if info, err = this.queryPlayerInfo(session.GetUserId()); err != nil && err != mgo.MongodbNil {
activated = false
info = nil
return
}
if err == mgo.MongodbNil {
global := this.module.ModuleTools.GetGlobalConf()
if global.ArenaTicketMax >= global.ArenaTicketCos.N {
ticket = global.ArenaTicketMax
activated = true
return
}
activated = false
}
activated = true
ticket = this.recoverTicket(session, info)
return
}
func (this *arenaModel) recoverTicket(session comm.IUserSession, info *pb.DBArenaUser) int32 {
var (
duration time.Duration
ticketitem *cfg.Gameatn
ticket int32
ticketNum int32
)
if ticketitem = this.module.ModuleTools.GetGlobalConf().ArenaTicketCos; ticketitem == nil {
this.module.Error("竞技场配置未找到!", log.Field{Key: "key", Value: "ArenaTicketCos"})
return 0
}
global := this.module.ModuleTools.GetGlobalConf()
maxTick := global.ArenaTicketMax
// 竞技场最大上限
maxTick += this.module.privilege.GetCountByPrivilegeId(session.GetUserId(), comm.PrivilegeType10) // 特权
ticket = int32(this.module.ModuleItems.QueryItemAmount(info.Uinfo.Uid, ticketitem.T))
if ticket < maxTick && info.Lastrtickettime > 0 {
duration = configure.Now().Sub(time.Unix(info.Lastrtickettime, 0))
ticketNum = int32(math.Floor(duration.Minutes() / float64(global.ArenaTicketRecoveryTime)))
if ticketNum > 0 {
if ticketNum+ticket > global.ArenaTicketMax {
ticketNum = global.ArenaTicketMax - ticket
}
this.module.DispenseRes(session, []*cfg.Gameatn{{A: ticketitem.A, T: ticketitem.T, N: ticketNum}}, true)
info.Lastrtickettime = time.Unix(info.Lastrtickettime, 0).Add(time.Duration(ticketNum) * time.Minute).Unix()
}
}
return ticket
}