1
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
昔念
2026-04-26 02:33:06 +08:00
parent 4906197c77
commit c07e521e4e
12 changed files with 265 additions and 348 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,153 +1,52 @@
# 巅峰之战天选池当前逻辑说明 # 巅峰之战天选池当前逻辑说明
更新时间2026-04-25 更新时间2026-04-26
## 1. 入口职责 ## 1. 入口职责
当前巅峰相关入口拆成 3 个点 - `point_1`巅峰之战主页面展示当前玩家已配置的天选精灵
- `point_2`天选池投票页面只保存玩家本周投票
- `point_3`天选精灵配置页面配置玩家自己的天选精灵属性
- `point_1`打开巅峰之战主页面 ## 2. 投票数据
- `point_2`打开天选池投票页面
- `point_3`打开本周正式天选配置页面
三者职责如下 投票表是 `config_peak_tianxuan_vote`
- `point_1` 只负责展示当前赛季段位匹配入口以及本周正式天选摘要 字段口径
- `point_2` 只负责玩家投票不负责配置本周正式天选属性
- `point_3` 只负责配置本周正式天选和其预设属性
## 2. 两套数据的区别 - `week_index`日期周格式为 ISO 年周例如 `202617`
- `player_id`投票玩家
- `pet_id`投票精灵
当前天选系统明确分成两套数据 约束口径
### 2.1 投票候选池 - 每个玩家每个日期周只能投 1 只精灵
- 同周重复投票时更新原记录
- 票数统计按 `week_index + pet_id` 聚合
这是玩家在 `point_2` 页面看到并进行投票的候选列表 ## 3. 投票池
来源规则 `point_2` 的候选池来自乱斗精灵池 `config_boss_melee` `mon_id` 去重
1. 先读取乱斗精灵池 `config_boss_melee` 当前不再因为上周出现过就从候选池移除上周投票结果只作为展示和后续配置参考
2. 从乱斗池中提取精灵 ID `mon_id` 去重
3. 再减掉上一周已经作为正式天选出现过的精灵
4. 剩余结果作为本周投票候选池
也就是说 页面会展示
- `point_2` 不是手工配置候选池 - 当前日期周投票池
- `point_2` 候选池是乱斗池 - 上周正式天选 - 上一日期周投票统计
- 当前玩家本周已投的精灵
### 2.2 本周正式天选 ## 4. 天选配置
这是本周真正会进入巅峰/BP 的正式天选列表 天选配置表是 `config_peak_tianxuan`
来源规则 这张表现在表示玩家额外拥有的天选精灵配置参考 `player_pet` 的归属思路不再按周保存
1. `point_3` 页面手工配置 核心字段
2. 写入 `config_peak_tianxuan`
3. 每条记录保存精灵 ID周序号展示顺序属性技能皮肤等信息
也就是说
- 玩家投票结果不直接等于本周正式天选
- 真正进入 BP 的是 `point_3` 配置出来的本周正式天选
## 3. 上周去重规则
当前已经实现的去重口径如下
### 3.1 投票候选去重
`point_2` 候选池生成时会自动排除上一周正式天选出现过的精灵
表现为
- 后端会返回 `tianxuan_prev_week_pool`
- 前端投票页会显示上周周免 / 本周排除项
- 这些精灵不会再进入当前投票候选列表
### 3.2 正式天选去重
`point_3` 配置本周正式天选时后端会校验
- 同一周内不能重复配置同一只精灵
- 本周正式天选不能和上一周正式天选重复
## 4. 玩家投票规则
玩家在 `point_2` 投票页的规则如下
- 每个玩家每周只能投 1
当前投票不会写入 `player_pvp`而是单独写入周投票记录表
当前投票记录字段最小化为
- `week_index`
- `player_id` - `player_id`
- `pet_id` - `pet_id`
表结构
- `config_peak_tianxuan_vote`
约束规则
- 同一玩家同一周只能有 1 条投票记录
- 如果本周重复投票不新增记录直接更新该玩家本周那条记录的 `pet_id`
- `updateTime` 就是该玩家本周最近一次修改投票的时间
这份数据当前用途
- 作为本周玩家投票明细保留
- 用于统计本周每只候选精灵的总票数
这份数据当前不直接参与
- 巅峰匹配入队
- BP 本周正式天选生成
## 5. point_1 当前展示逻辑
巅峰主页面当前展示的是本周正式天选不是玩家投票候选池
页面会从 `/admin/game/pvp/get` 读取
- `current_tianxuan_pool`本周正式天选
- `tianxuan_vote_pool`本周投票候选池
- `tianxuan_prev_week_pool`上周正式天选用于排除展示
主页面当前重点展示
- 段位和匹配模式
- 本周正式天选数量
- 本周正式天选列表
## 6. point_2 当前展示逻辑
天选池投票页当前会
1. 请求 `/admin/game/pvp/get`
2. 读取 `tianxuan_vote_pool`
3. 读取 `tianxuan_prev_week_pool`
4. 读取 `selected_tianxuan_pet_ids`
5. 按当前段位限制可投数量
页面表现
- 顶部显示当前周和投票数量限制
- 单独显示上周周免 / 本周排除项
- 候选列表支持搜索
- 候选列表支持无限滚动懒加载
## 7. point_3 当前配置逻辑
`point_3` 对应的是本周正式天选配置面板
当前可配置字段包括
- `week_index`
- `display_order` - `display_order`
- `pet_id`
- `preset_name` - `preset_name`
- `level` - `level`
- `nature` - `nature`
@@ -164,66 +63,19 @@
- `remark` - `remark`
- `is_enable` - `is_enable`
存储表 约束口径
- `config_peak_tianxuan` - 同一玩家不能重复配置同一只天选精灵
- 不再校验本周不能和上周重复
- 不再要求 `week_index`
## 8. BP 当前使用逻辑 ## 5. BP 使用
BP 当前不再读取玩家投票结果 BP 不直接读取投票记录
当前口径 进入 BP 时读取双方各自的 `config_peak_tianxuan` 配置
- BP 使用的是本周正式天选 - 我方看到自己的天选配置
- 后端在进入 BP 时读取 `config_peak_tianxuan` 当前周配置 - 对方看到对方自己的天选配置
- 同一份正式天选会同时下发给双方展示
也就是说 投票结果后续可用于决定哪些精灵开放给玩家配置但配置本身是玩家维度的数据
- 玩家投票结果不直接进 BP
- `point_3` 配置才是真正进入 BP 的天选列表
## 9. 接口口径
### 9.1 `/admin/game/pvp/get`
当前主要返回
- `rank_info`
- `required_tianxuan_vote_count`
- `tianxuan_week_index`
- `tianxuan_prev_week_index`
- `tianxuan_vote_pool`
- `tianxuan_prev_week_pool`
- `current_tianxuan_pool`
### 9.2 `/admin/game/pvp/save_tianxuan_vote`
当前用途
- 保存玩家本周唯一一条投票记录
保存前会校验
- 只能投候选池中的精灵
- 每次只允许提交 1 只精灵
- 同一玩家同一周重复提交时覆盖原投票记录
## 10. 票数统计方式
候选列表中的票数不再存死值
当前实现为
1. 每周投票明细写入 `config_peak_tianxuan_vote`
2. 候选列表展示时 `week_index + pet_id` 聚合统计票数
3. 下一周如果要看上周投票结果直接统计上周的投票记录表即可
## 11. 当前已知口径总结
一句话总结当前逻辑
- `point_2`玩家从乱斗池 - 上周正式天选里投票
- `point_3`运营/配置侧手工配置本周正式天选和属性
- `point_1` / BP都使用 `point_3` 配好的本周正式天选
- 玩家投票明细单独存 `config_peak_tianxuan_vote`不进 `player_pvp`

View File

@@ -31,6 +31,13 @@ func (e *NewSel0) IsOwner() bool {
return e.ID().GetCatchTime() == source.CurPet[0].Info.CatchTime return e.ID().GetCatchTime() == source.CurPet[0].Info.CatchTime
} }
func (e *NewSel0) CurrentSkillHit() bool {
if e.Ctx().SkillEntity == nil {
return false
}
return e.Ctx().SkillEntity.AttackTime != 0
}
// 免疫"能力(battle_lv)下降" // 免疫"能力(battle_lv)下降"
type NewSel1 struct { type NewSel1 struct {
NewSel0 NewSel0

View File

@@ -28,6 +28,9 @@ func (e *NewSel49) Action_end_ex() bool {
if e.Ctx().SkillEntity == nil { if e.Ctx().SkillEntity == nil {
return true return true
} }
if !e.CurrentSkillHit() {
return true
}
if e.Ctx().SkillEntity.Category() == info.Category.PHYSICAL { if e.Ctx().SkillEntity.Category() == info.Category.PHYSICAL {
e.attackType = 1 e.attackType = 1

View File

@@ -22,6 +22,9 @@ func (e *NewSel6) Action_end_ex() bool {
if e.Ctx().SkillEntity.Category() != info.Category.PHYSICAL { if e.Ctx().SkillEntity.Category() != info.Category.PHYSICAL {
return true return true
} }
if !e.CurrentSkillHit() {
return true
}
// 3. 概率判定Args()[1]为触发概率) // 3. 概率判定Args()[1]为触发概率)
success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100) success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100)

View File

@@ -23,6 +23,9 @@ func (e *NewSel74) Action_end_ex() bool {
if e.Ctx().SkillEntity.Category() == info.Category.STATUS { if e.Ctx().SkillEntity.Category() == info.Category.STATUS {
return true return true
} }
if !e.CurrentSkillHit() {
return true
}
// 检查概率是否触发 // 检查概率是否触发
success, _, _ := e.Input.Player.Roll(int(e.Args()[0].IntPart()), 100) success, _, _ := e.Input.Player.Roll(int(e.Args()[0].IntPart()), 100)

View File

@@ -23,6 +23,9 @@ func (e *NewSel78) Action_end_ex() bool {
if e.Ctx().SkillEntity.Category() != info.Category.SPECIAL { if e.Ctx().SkillEntity.Category() != info.Category.SPECIAL {
return true return true
} }
if !e.CurrentSkillHit() {
return true
}
// 检查概率是否触发 // 检查概率是否触发
success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100) success, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100)

View File

@@ -19,9 +19,9 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
configservice "blazing/modules/config/service"
"blazing/modules/player/model" "blazing/modules/player/model"
blservice "blazing/modules/player/service" blservice "blazing/modules/player/service"
configservice "blazing/modules/config/service"
) )
const ( const (
@@ -583,7 +583,8 @@ func newQueueKey(player pvpwire.QueuePlayerSnapshot) queueKey {
func newBanPickStartInfo(match pvpwire.MatchFoundPayload, self, opponent pvpwire.QueuePlayerSnapshot) *fight.CrossServerBanPickStartOutboundInfo { func newBanPickStartInfo(match pvpwire.MatchFoundPayload, self, opponent pvpwire.QueuePlayerSnapshot) *fight.CrossServerBanPickStartOutboundInfo {
myPets := buildBanPickPetInfos(self.CatchTimes) myPets := buildBanPickPetInfos(self.CatchTimes)
opponentPets := buildBanPickPetInfos(opponent.CatchTimes) opponentPets := buildBanPickPetInfos(opponent.CatchTimes)
currentTianxuanPets := buildCurrentWeekTianxuanPetInfos() myTianxuanPets := buildCurrentWeekTianxuanPetInfos(self.UserID)
opponentTianxuanPets := buildCurrentWeekTianxuanPetInfos(opponent.UserID)
return &fight.CrossServerBanPickStartOutboundInfo{ return &fight.CrossServerBanPickStartOutboundInfo{
SessionID: match.SessionID, SessionID: match.SessionID,
OpponentUserID: opponent.UserID, OpponentUserID: opponent.UserID,
@@ -592,11 +593,11 @@ func newBanPickStartInfo(match pvpwire.MatchFoundPayload, self, opponent pvpwire
Status: self.Status, Status: self.Status,
TimeoutSeconds: match.BanPickTimeout, TimeoutSeconds: match.BanPickTimeout,
SelectableCount: uint32(minInt(battlePetLimit(self.FightMode), len(myPets))), SelectableCount: uint32(minInt(battlePetLimit(self.FightMode), len(myPets))),
TianxuanSelectableCount: uint32(len(currentTianxuanPets)), TianxuanSelectableCount: uint32(len(myTianxuanPets)),
MyPets: myPets, MyPets: myPets,
MyTianxuanPets: currentTianxuanPets, MyTianxuanPets: myTianxuanPets,
OpponentPets: opponentPets, OpponentPets: opponentPets,
OpponentTianxuanPets: currentTianxuanPets, OpponentTianxuanPets: opponentTianxuanPets,
} }
} }
@@ -752,8 +753,8 @@ func buildTianxuanPetInfos(petIDs []uint32) []fight.CrossServerBanPickTianxuanPe
return result return result
} }
func buildCurrentWeekTianxuanPetInfos() []fight.CrossServerBanPickTianxuanPetInfo { func buildCurrentWeekTianxuanPetInfos(playerID uint32) []fight.CrossServerBanPickTianxuanPetInfo {
petIDs, err := configservice.NewPeakTianxuanService().CurrentTianxuanPetIDs() petIDs, err := configservice.NewPeakTianxuanService().CurrentTianxuanPetIDs(playerID)
if err != nil { if err != nil {
return nil return nil
} }

View File

@@ -11,9 +11,9 @@ const (
type PeakTianxuan struct { type PeakTianxuan struct {
*BaseConfig *BaseConfig
WeekIndex uint32 `gorm:"not null;index:idx_peak_tianxuan_week;uniqueIndex:idx_peak_tianxuan_week_pet;comment:'周序号'" json:"week_index"` PlayerID uint32 `gorm:"not null;index:idx_peak_tianxuan_player;uniqueIndex:idx_peak_tianxuan_player_pet;comment:'所属玩家ID'" json:"player_id"`
DisplayOrder uint32 `gorm:"not null;default:0;comment:'展示顺序'" json:"display_order"` DisplayOrder uint32 `gorm:"not null;default:0;comment:'展示顺序'" json:"display_order"`
PetID uint32 `gorm:"not null;uniqueIndex:idx_peak_tianxuan_week_pet;comment:'天选精灵ID'" json:"pet_id"` PetID uint32 `gorm:"not null;uniqueIndex:idx_peak_tianxuan_player_pet;comment:'天选精灵ID'" json:"pet_id"`
PresetName string `gorm:"type:varchar(64);not null;default:'';comment:'预设显示名'" json:"preset_name"` PresetName string `gorm:"type:varchar(64);not null;default:'';comment:'预设显示名'" json:"preset_name"`
Level uint32 `gorm:"not null;default:100;comment:'预设等级'" json:"level"` Level uint32 `gorm:"not null;default:100;comment:'预设等级'" json:"level"`
Nature uint32 `gorm:"not null;default:0;comment:'预设性格'" json:"nature"` Nature uint32 `gorm:"not null;default:0;comment:'预设性格'" json:"nature"`

View File

@@ -2,6 +2,7 @@ package service
import ( import (
"context" "context"
"time"
"blazing/common/data/xmlres" "blazing/common/data/xmlres"
"blazing/cool" "blazing/cool"
@@ -22,20 +23,36 @@ func NewPeakTianxuanService() *PeakTianxuanService {
return &PeakTianxuanService{ return &PeakTianxuanService{
&cool.Service{ &cool.Service{
Model: model.NewPeakTianxuan(), Model: model.NewPeakTianxuan(),
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
InsertParam: func(ctx context.Context) g.MapStrAny {
admin := cool.GetAdmin(ctx)
return g.MapStrAny{
"player_id": uint32(admin.UserId),
}
},
PageQueryOp: &cool.QueryOp{ PageQueryOp: &cool.QueryOp{
KeyWordField: []string{"preset_name", "remark"}, KeyWordField: []string{"preset_name", "remark"},
FieldEQ: []string{"week_index", "pet_id", "is_enable"}, FieldEQ: []string{"player_id", "pet_id", "is_enable"},
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
AddOrderby: g.MapStrStr{ AddOrderby: g.MapStrStr{
"week_index": "desc",
"display_order": "asc", "display_order": "asc",
"id": "desc", "id": "desc",
}, },
}, },
ListQueryOp: &cool.QueryOp{ ListQueryOp: &cool.QueryOp{
KeyWordField: []string{"preset_name", "remark"}, KeyWordField: []string{"preset_name", "remark"},
FieldEQ: []string{"week_index", "pet_id", "is_enable"}, FieldEQ: []string{"player_id", "pet_id", "is_enable"},
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
AddOrderby: g.MapStrStr{ AddOrderby: g.MapStrStr{
"week_index": "desc",
"display_order": "asc", "display_order": "asc",
"id": "desc", "id": "desc",
}, },
@@ -49,8 +66,11 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
return nil return nil
} }
admin := cool.GetAdmin(ctx)
param["player_id"] = uint32(admin.UserId)
var ( var (
weekIndex = gconv.Uint32(param["week_index"]) playerID = gconv.Uint32(param["player_id"])
petID = gconv.Uint32(param["pet_id"]) petID = gconv.Uint32(param["pet_id"])
level = gconv.Uint32(param["level"]) level = gconv.Uint32(param["level"])
hp = gconv.Uint32(param["hp"]) hp = gconv.Uint32(param["hp"])
@@ -58,8 +78,8 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
recordID = gconv.Uint32(param["id"]) recordID = gconv.Uint32(param["id"])
) )
if weekIndex == 0 { if playerID == 0 {
return gerror.New("周序号不能为空") return gerror.New("配置玩家不能为空")
} }
if petID == 0 { if petID == 0 {
return gerror.New("天选精灵ID不能为空") return gerror.New("天选精灵ID不能为空")
@@ -72,7 +92,9 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
} }
var currentCount int var currentCount int
query := cool.DBM(s.Model).Where("week_index", weekIndex).Where("pet_id", petID) query := cool.DBM(s.Model).
Where("player_id", playerID).
Where("pet_id", petID)
if recordID > 0 { if recordID > 0 {
query = query.WhereNot("id", recordID) query = query.WhereNot("id", recordID)
} }
@@ -80,72 +102,67 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
return err return err
} }
if currentCount > 0 { if currentCount > 0 {
return gerror.New("同一不能重复配置同一只天选精灵") return gerror.New("同一玩家不能重复配置同一只天选精灵")
}
prevPetIDs, err := s.ListWeekPetIDs(weekIndex - 1)
if err != nil {
return err
}
if _, ok := prevPetIDs[petID]; ok {
return gerror.New("本周天选精灵不能和上一周重复")
} }
return nil return nil
} }
func (s *PeakTianxuanService) LatestWeekIndex() (uint32, error) { func dateWeekIndex(t time.Time) uint32 {
var result struct { year, week := t.ISOWeek()
WeekIndex uint32 `json:"week_index"` return uint32(year*100 + week)
} }
if err := dbm_nocache_noenable(s.Model). func currentDateWeekIndex() uint32 {
Fields("COALESCE(MAX(week_index), 0) AS week_index"). return dateWeekIndex(time.Now())
Scan(&result); err != nil {
return 0, err
} }
return result.WeekIndex, nil func prevDateWeekIndex() uint32 {
return dateWeekIndex(time.Now().AddDate(0, 0, -7))
} }
func (s *PeakTianxuanService) ListWeekPetIDs(weekIndex uint32) (map[uint32]struct{}, error) { func (s *PeakTianxuanService) CurrentVoteWeekIndex() (uint32, uint32, error) {
return currentDateWeekIndex(), prevDateWeekIndex(), nil
}
func (s *PeakTianxuanService) ListWeekPetIDs(weekIndex uint32, playerIDs ...uint32) (map[uint32]struct{}, error) {
ret := make(map[uint32]struct{}) ret := make(map[uint32]struct{})
if weekIndex == 0 { if weekIndex == 0 {
return ret, nil return ret, nil
} }
var list []model.PeakTianxuan var voteRows []struct {
if err := dbm_enable(s.Model).Where("week_index", weekIndex).Scan(&list); err != nil { PetID uint32 `json:"pet_id"`
}
if err := cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id").
Where("week_index", weekIndex).
Group("pet_id").
Scan(&voteRows); err != nil {
return nil, err return nil, err
} }
for _, item := range list { for _, item := range voteRows {
ret[item.PetID] = struct{}{} ret[item.PetID] = struct{}{}
} }
return ret, nil return ret, nil
} }
func (s *PeakTianxuanService) GetWeekList(weekIndex uint32) ([]model.PeakTianxuan, error) { func (s *PeakTianxuanService) GetWeekList(weekIndex uint32, playerIDs ...uint32) ([]model.PeakTianxuan, error) {
var list []model.PeakTianxuan var list []model.PeakTianxuan
if weekIndex == 0 {
return list, nil
}
err := dbm_enable(s.Model). query := dbm_enable(s.Model)
Where("week_index", weekIndex). if len(playerIDs) > 0 && playerIDs[0] > 0 {
Order("display_order asc,id asc"). query = query.Where("player_id", playerIDs[0])
Scan(&list) }
err := query.Order("display_order asc,id asc").Scan(&list)
return list, err return list, err
} }
func (s *PeakTianxuanService) GetCurrentWeekList() ([]model.PeakTianxuan, uint32, error) { func (s *PeakTianxuanService) GetCurrentWeekList(playerIDs ...uint32) ([]model.PeakTianxuan, uint32, error) {
weekIndex, err := s.LatestWeekIndex() weekIndex := currentDateWeekIndex()
if err != nil || weekIndex == 0 { list, err := s.GetWeekList(0, playerIDs...)
return nil, weekIndex, err
}
list, err := s.GetWeekList(weekIndex)
return list, weekIndex, err return list, weekIndex, err
} }
@@ -186,24 +203,21 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
return 0, gerror.New("投票精灵不在候选池中") return 0, gerror.New("投票精灵不在候选池中")
} }
currentWeekIndex, err := s.LatestWeekIndex() voteWeekIndex, _, err := s.CurrentVoteWeekIndex()
if err != nil { if err != nil {
return 0, err return 0, err
} }
if currentWeekIndex == 0 {
currentWeekIndex = 1
}
voteModel := model.NewPeakTianxuanVote() voteModel := model.NewPeakTianxuanVote()
data := model.PeakTianxuanVote{ data := model.PeakTianxuanVote{
WeekIndex: currentWeekIndex, WeekIndex: voteWeekIndex,
PlayerID: playerID, PlayerID: playerID,
PetID: normalize[0], PetID: normalize[0],
} }
var count int var count int
count, err = cool.DBM(voteModel). count, err = cool.DBM(voteModel).
Where("week_index", currentWeekIndex). Where("week_index", voteWeekIndex).
Where("player_id", playerID). Where("player_id", playerID).
Count() Count()
if err != nil { if err != nil {
@@ -211,7 +225,7 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
} }
if count > 0 { if count > 0 {
_, err = cool.DBM(voteModel). _, err = cool.DBM(voteModel).
Where("week_index", currentWeekIndex). Where("week_index", voteWeekIndex).
Where("player_id", playerID). Where("player_id", playerID).
Data(data). Data(data).
Update() Update()
@@ -225,8 +239,35 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
return normalize[0], nil return normalize[0], nil
} }
func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, error) { func (s *PeakTianxuanService) GetPlayerVote(playerID uint32) (uint32, error) {
list, weekIndex, err := s.GetCurrentWeekList() voteWeekIndex, prevWeekIndex, err := s.CurrentVoteWeekIndex()
if err != nil {
return 0, err
}
var vote model.PeakTianxuanVote
if err = cool.DBM(model.NewPeakTianxuanVote()).
Where("week_index", voteWeekIndex).
Where("player_id", playerID).
Scan(&vote); err != nil {
return 0, err
}
if vote.PetID > 0 || prevWeekIndex == 0 {
return vote.PetID, nil
}
// 兼容旧数据:之前投票可能写在“当前正式周”里,打开页面仍需标出玩家已选。
if err = cool.DBM(model.NewPeakTianxuanVote()).
Where("week_index", prevWeekIndex).
Where("player_id", playerID).
Scan(&vote); err != nil {
return 0, err
}
return vote.PetID, nil
}
func (s *PeakTianxuanService) BuildCurrentTianxuanPayload(playerIDs ...uint32) ([]g.Map, uint32, error) {
list, weekIndex, err := s.GetCurrentWeekList(playerIDs...)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
@@ -241,7 +282,7 @@ func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, er
} }
ret = append(ret, g.Map{ ret = append(ret, g.Map{
"id": item.ID, "id": item.ID,
"week_index": item.WeekIndex, "player_id": item.PlayerID,
"display_order": item.DisplayOrder, "display_order": item.DisplayOrder,
"pet_id": item.PetID, "pet_id": item.PetID,
"petId": item.PetID, "petId": item.PetID,
@@ -269,30 +310,19 @@ func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, er
} }
func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32, uint32, error) { func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32, uint32, error) {
currentWeekIndex, err := s.LatestWeekIndex() voteWeekIndex, prevWeekIndex, err := s.CurrentVoteWeekIndex()
if err != nil {
return nil, 0, 0, err
}
prevWeekIndex := uint32(0)
if currentWeekIndex > 1 {
prevWeekIndex = currentWeekIndex - 1
}
prevWeekPetIDs, err := s.ListWeekPetIDs(prevWeekIndex)
if err != nil { if err != nil {
return nil, 0, 0, err return nil, 0, 0, err
} }
currentWeekVoteMap := make(map[uint32]uint32) currentWeekVoteMap := make(map[uint32]uint32)
if currentWeekIndex > 0 {
var voteRows []struct { var voteRows []struct {
PetID uint32 `json:"pet_id"` PetID uint32 `json:"pet_id"`
VoteCount uint32 `json:"vote_count"` VoteCount uint32 `json:"vote_count"`
} }
if err = cool.DBM(model.NewPeakTianxuanVote()). if err = cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id, COUNT(1) AS vote_count"). Fields("pet_id, COUNT(1) AS vote_count").
Where("week_index", currentWeekIndex). Where("week_index", voteWeekIndex).
Group("pet_id"). Group("pet_id").
Scan(&voteRows); err != nil { Scan(&voteRows); err != nil {
return nil, 0, 0, err return nil, 0, 0, err
@@ -300,7 +330,6 @@ func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32,
for _, item := range voteRows { for _, item := range voteRows {
currentWeekVoteMap[item.PetID] = item.VoteCount currentWeekVoteMap[item.PetID] = item.VoteCount
} }
}
var meleeList []model.PetBaseConfig var meleeList []model.PetBaseConfig
if err = cool.DBM(model.NewMeettConfig()).Order("mon_id asc").Scan(&meleeList); err != nil { if err = cool.DBM(model.NewMeettConfig()).Order("mon_id asc").Scan(&meleeList); err != nil {
@@ -318,9 +347,6 @@ func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32,
if petID == 0 { if petID == 0 {
continue continue
} }
if _, ok := prevWeekPetIDs[petID]; ok {
continue
}
if _, ok := unique[petID]; ok { if _, ok := unique[petID]; ok {
continue continue
} }
@@ -354,11 +380,11 @@ func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32,
}) })
} }
return ret, currentWeekIndex, prevWeekIndex, nil return ret, voteWeekIndex, prevWeekIndex, nil
} }
func (s *PeakTianxuanService) CurrentTianxuanPetIDs() ([]uint32, error) { func (s *PeakTianxuanService) CurrentTianxuanPetIDs(playerIDs ...uint32) ([]uint32, error) {
list, _, err := s.GetCurrentWeekList() list, _, err := s.GetCurrentWeekList(playerIDs...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -374,42 +400,30 @@ func (s *PeakTianxuanService) CurrentTianxuanPetIDs() ([]uint32, error) {
} }
func (s *PeakTianxuanService) BuildWeekTianxuanPayload(weekIndex uint32) ([]g.Map, error) { func (s *PeakTianxuanService) BuildWeekTianxuanPayload(weekIndex uint32) ([]g.Map, error) {
list, err := s.GetWeekList(weekIndex) var voteRows []struct {
if err != nil { PetID uint32 `json:"pet_id"`
VoteCount uint32 `json:"vote_count"`
}
if err := cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id, COUNT(1) AS vote_count").
Where("week_index", weekIndex).
Group("pet_id").
Order("vote_count desc, pet_id asc").
Scan(&voteRows); err != nil {
return nil, err return nil, err
} }
ret := make([]g.Map, 0, len(list)) ret := make([]g.Map, 0, len(voteRows))
for _, item := range list { for _, item := range voteRows {
name := item.PresetName name := ""
if name == "" {
if pet, ok := xmlres.PetMAP[int(item.PetID)]; ok { if pet, ok := xmlres.PetMAP[int(item.PetID)]; ok {
name = pet.DefName name = pet.DefName
} }
}
ret = append(ret, g.Map{ ret = append(ret, g.Map{
"id": item.ID,
"week_index": item.WeekIndex,
"display_order": item.DisplayOrder,
"pet_id": item.PetID, "pet_id": item.PetID,
"petId": item.PetID, "petId": item.PetID,
"name": name, "name": name,
"preset_name": item.PresetName,
"level": item.Level,
"nature": item.Nature,
"hp": item.Hp,
"max_hp": item.MaxHp,
"attack": item.Attack,
"defence": item.Defence,
"sp_attack": item.SpAttack,
"sp_defence": item.SpDefence,
"speed": item.Speed,
"skin_id": item.SkinID,
"effect_ids": item.EffectIDs,
"skill_ids": item.SkillIDs,
"vote_count": item.VoteCount, "vote_count": item.VoteCount,
"is_enable": item.IsEnable,
"remark": item.Remark,
}) })
} }

View File

@@ -39,18 +39,23 @@ func (c *PVPController) Get(ctx context.Context, req *GetPVPReq) (res *cool.Base
votePool []g.Map votePool []g.Map
currentPool []g.Map currentPool []g.Map
prevWeekPool []g.Map prevWeekPool []g.Map
playerVotePetID uint32
weekIndex uint32 weekIndex uint32
prevWeekIndex uint32 prevWeekIndex uint32
) )
if votePool, weekIndex, prevWeekIndex, err = tianxuanSv.BuildVoteCandidatePoolPayload(); err != nil { if votePool, weekIndex, prevWeekIndex, err = tianxuanSv.BuildVoteCandidatePoolPayload(); err != nil {
return return
} }
if currentPool, _, err = tianxuanSv.BuildCurrentTianxuanPayload(); err != nil { if currentPool, _, err = tianxuanSv.BuildCurrentTianxuanPayload(uint32(admin.UserId)); err != nil {
return return
} }
if prevWeekPool, err = tianxuanSv.BuildWeekTianxuanPayload(prevWeekIndex); err != nil { if prevWeekPool, err = tianxuanSv.BuildWeekTianxuanPayload(prevWeekIndex); err != nil {
return return
} }
if playerVotePetID, err = tianxuanSv.GetPlayerVote(uint32(admin.UserId)); err != nil {
return
}
markMyTianxuanVote(votePool, playerVotePetID)
res.Data = g.Map{ res.Data = g.Map{
"id": pvpInfo.ID, "id": pvpInfo.ID,
@@ -63,6 +68,7 @@ func (c *PVPController) Get(ctx context.Context, req *GetPVPReq) (res *cool.Base
"tianxuan_vote_pool": votePool, "tianxuan_vote_pool": votePool,
"tianxuan_prev_week_pool": prevWeekPool, "tianxuan_prev_week_pool": prevWeekPool,
"current_tianxuan_pool": currentPool, "current_tianxuan_pool": currentPool,
"my_tianxuan_vote_pet_id": playerVotePetID,
} }
return return
@@ -78,8 +84,12 @@ func (c *PVPController) SaveTianxuanVote(ctx context.Context, req *SaveTianxuanV
var ( var (
admin = cool.GetAdmin(ctx) admin = cool.GetAdmin(ctx)
tianxuanSv = configService.NewPeakTianxuanService()
petID uint32 petID uint32
saved uint32 saved uint32
votePool []g.Map
weekIndex uint32
prevWeekIndex uint32
) )
for _, item := range req.PetIDs { for _, item := range req.PetIDs {
@@ -90,13 +100,34 @@ func (c *PVPController) SaveTianxuanVote(ctx context.Context, req *SaveTianxuanV
break break
} }
if saved, err = configService.NewPeakTianxuanService().SaveVote(uint32(admin.UserId), petID); err != nil { if saved, err = tianxuanSv.SaveVote(uint32(admin.UserId), petID); err != nil {
return return
} }
if votePool, weekIndex, prevWeekIndex, err = tianxuanSv.BuildVoteCandidatePoolPayload(); err != nil {
return
}
markMyTianxuanVote(votePool, saved)
res.Data = g.Map{ res.Data = g.Map{
"saved_pet_id": saved, "saved_pet_id": saved,
"my_tianxuan_vote_pet_id": saved,
"required_tianxuan_vote_count": 1, "required_tianxuan_vote_count": 1,
"tianxuan_week_index": weekIndex,
"tianxuan_prev_week_index": prevWeekIndex,
"tianxuan_vote_pool": votePool,
} }
return return
} }
func markMyTianxuanVote(votePool []g.Map, petID uint32) {
if petID == 0 {
return
}
for _, item := range votePool {
if gconv.Uint32(item["pet_id"]) == petID || gconv.Uint32(item["petId"]) == petID {
item["is_voted"] = true
item["isVoted"] = true
return
}
}
}

View File

@@ -1,3 +1,3 @@
{ {
"current_season": 5 "current_season": 0
} }