mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 05:43:41 +03:00
Implement Fate Boards
Build and Push Docker images to Docker Hub / build-and-push (push) Has been cancelled
Build and Push Docker images to Docker Hub / build-and-push (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
package masterdata
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"lunar-tear/server/internal/utils"
|
||||
)
|
||||
|
||||
type LabyrinthChapter struct {
|
||||
EventQuestChapterId int32
|
||||
LatestSeasonNumber int32
|
||||
StageOrders []int32
|
||||
}
|
||||
|
||||
type LabyrinthStageTier struct {
|
||||
QuestMissionClearCount int32
|
||||
Rewards []RewardItem
|
||||
}
|
||||
|
||||
type LabyrinthSeasonMilestone struct {
|
||||
HeadQuestId int32
|
||||
HeadStageOrder int32
|
||||
Rewards []RewardItem
|
||||
}
|
||||
|
||||
type labyrinthStageKey struct {
|
||||
ChapterId int32
|
||||
StageOrder int32
|
||||
}
|
||||
|
||||
type LabyrinthCatalog struct {
|
||||
ChaptersByOrder []LabyrinthChapter
|
||||
ClearRewardsByStage map[labyrinthStageKey][]RewardItem
|
||||
AccumTiersByStage map[labyrinthStageKey][]LabyrinthStageTier
|
||||
SeasonMilestonesByChapter map[int32][]LabyrinthSeasonMilestone
|
||||
}
|
||||
|
||||
func (c *LabyrinthCatalog) StageClearReward(chapterId, stageOrder int32) []RewardItem {
|
||||
return c.ClearRewardsByStage[labyrinthStageKey{chapterId, stageOrder}]
|
||||
}
|
||||
|
||||
func (c *LabyrinthCatalog) CollectAccumulationRewards(chapterId, stageOrder, oldCount, targetCount int32) ([]RewardItem, int32) {
|
||||
var items []RewardItem
|
||||
highest := int32(0)
|
||||
for _, t := range c.AccumTiersByStage[labyrinthStageKey{chapterId, stageOrder}] {
|
||||
if t.QuestMissionClearCount > oldCount && t.QuestMissionClearCount <= targetCount {
|
||||
items = append(items, t.Rewards...)
|
||||
if t.QuestMissionClearCount > highest {
|
||||
highest = t.QuestMissionClearCount
|
||||
}
|
||||
}
|
||||
}
|
||||
return items, highest
|
||||
}
|
||||
|
||||
func (c *LabyrinthCatalog) SeasonMilestones(chapterId int32) []LabyrinthSeasonMilestone {
|
||||
return c.SeasonMilestonesByChapter[chapterId]
|
||||
}
|
||||
|
||||
func LoadLabyrinthCatalog() *LabyrinthCatalog {
|
||||
seasonRows, err := utils.ReadTable[EntityMEventQuestLabyrinthSeason]("m_event_quest_labyrinth_season")
|
||||
if err != nil {
|
||||
log.Printf("[labyrinth] m_event_quest_labyrinth_season unavailable, labyrinth disabled: %v", err)
|
||||
return &LabyrinthCatalog{}
|
||||
}
|
||||
stageRows, err := utils.ReadTable[EntityMEventQuestLabyrinthStage]("m_event_quest_labyrinth_stage")
|
||||
if err != nil {
|
||||
log.Printf("[labyrinth] m_event_quest_labyrinth_stage unavailable, labyrinth disabled: %v", err)
|
||||
return &LabyrinthCatalog{}
|
||||
}
|
||||
|
||||
// chapterId -> highest SeasonNumber
|
||||
latestSeason := make(map[int32]int32)
|
||||
for _, r := range seasonRows {
|
||||
if r.SeasonNumber > latestSeason[r.EventQuestChapterId] {
|
||||
latestSeason[r.EventQuestChapterId] = r.SeasonNumber
|
||||
}
|
||||
}
|
||||
// chapterId -> stage orders
|
||||
stagesByChapter := make(map[int32][]int32)
|
||||
for _, r := range stageRows {
|
||||
stagesByChapter[r.EventQuestChapterId] = append(stagesByChapter[r.EventQuestChapterId], r.StageOrder)
|
||||
}
|
||||
|
||||
chapters := make([]LabyrinthChapter, 0, len(latestSeason))
|
||||
for chapterId, season := range latestSeason {
|
||||
stages := stagesByChapter[chapterId]
|
||||
sort.Slice(stages, func(i, j int) bool { return stages[i] < stages[j] })
|
||||
chapters = append(chapters, LabyrinthChapter{
|
||||
EventQuestChapterId: chapterId,
|
||||
LatestSeasonNumber: season,
|
||||
StageOrders: stages,
|
||||
})
|
||||
}
|
||||
sort.Slice(chapters, func(i, j int) bool {
|
||||
return chapters[i].EventQuestChapterId < chapters[j].EventQuestChapterId
|
||||
})
|
||||
|
||||
clearRewards, accumTiers, seasonMilestones := loadLabyrinthRewards(seasonRows, stageRows)
|
||||
|
||||
log.Printf("labyrinth catalog loaded: %d chapters, %d stages with clear rewards, %d with accumulation rewards, %d chapters with season rewards",
|
||||
len(chapters), len(clearRewards), len(accumTiers), len(seasonMilestones))
|
||||
return &LabyrinthCatalog{
|
||||
ChaptersByOrder: chapters,
|
||||
ClearRewardsByStage: clearRewards,
|
||||
AccumTiersByStage: accumTiers,
|
||||
SeasonMilestonesByChapter: seasonMilestones,
|
||||
}
|
||||
}
|
||||
|
||||
func loadLabyrinthRewards(seasonRows []EntityMEventQuestLabyrinthSeason, stageRows []EntityMEventQuestLabyrinthStage) (
|
||||
clearRewards map[labyrinthStageKey][]RewardItem,
|
||||
accumTiers map[labyrinthStageKey][]LabyrinthStageTier,
|
||||
seasonMilestones map[int32][]LabyrinthSeasonMilestone,
|
||||
) {
|
||||
rewardGroupRows, err := utils.ReadTable[EntityMEventQuestLabyrinthRewardGroup]("m_event_quest_labyrinth_reward_group")
|
||||
if err != nil {
|
||||
log.Printf("[labyrinth] m_event_quest_labyrinth_reward_group unavailable, rewards disabled: %v", err)
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// reward group id -> reward items
|
||||
itemsByRewardGroup := make(map[int32][]RewardItem)
|
||||
for _, r := range rewardGroupRows {
|
||||
itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId] = append(itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId], RewardItem{
|
||||
PossessionType: r.PossessionType,
|
||||
PossessionId: r.PossessionId,
|
||||
Count: r.Count,
|
||||
})
|
||||
}
|
||||
|
||||
// per-stage one-time clear reward
|
||||
clearRewards = make(map[labyrinthStageKey][]RewardItem)
|
||||
for _, r := range stageRows {
|
||||
if r.StageClearRewardGroupId == 0 {
|
||||
continue
|
||||
}
|
||||
if items := itemsByRewardGroup[r.StageClearRewardGroupId]; len(items) > 0 {
|
||||
clearRewards[labyrinthStageKey{r.EventQuestChapterId, r.StageOrder}] = items
|
||||
}
|
||||
}
|
||||
|
||||
if accumGroupRows, err := utils.ReadTable[EntityMEventQuestLabyrinthStageAccumulationRewardGroup]("m_event_quest_labyrinth_stage_accumulation_reward_group"); err != nil {
|
||||
log.Printf("[labyrinth] m_event_quest_labyrinth_stage_accumulation_reward_group unavailable, accumulation rewards disabled: %v", err)
|
||||
} else {
|
||||
// accumulation group id -> tiers (threshold + resolved reward items)
|
||||
tiersByGroup := make(map[int32][]LabyrinthStageTier)
|
||||
for _, r := range accumGroupRows {
|
||||
tiersByGroup[r.EventQuestLabyrinthStageAccumulationRewardGroupId] = append(tiersByGroup[r.EventQuestLabyrinthStageAccumulationRewardGroupId], LabyrinthStageTier{
|
||||
QuestMissionClearCount: r.QuestMissionClearCount,
|
||||
Rewards: itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
||||
})
|
||||
}
|
||||
accumTiers = make(map[labyrinthStageKey][]LabyrinthStageTier)
|
||||
for _, r := range stageRows {
|
||||
if r.StageAccumulationRewardGroupId == 0 {
|
||||
continue
|
||||
}
|
||||
tiers := tiersByGroup[r.StageAccumulationRewardGroupId]
|
||||
sort.Slice(tiers, func(i, j int) bool {
|
||||
return tiers[i].QuestMissionClearCount < tiers[j].QuestMissionClearCount
|
||||
})
|
||||
accumTiers[labyrinthStageKey{r.EventQuestChapterId, r.StageOrder}] = tiers
|
||||
}
|
||||
}
|
||||
|
||||
// per-chapter season-reward milestones
|
||||
if seasonRewardRows, err := utils.ReadTable[EntityMEventQuestLabyrinthSeasonRewardGroup]("m_event_quest_labyrinth_season_reward_group"); err != nil {
|
||||
log.Printf("[labyrinth] m_event_quest_labyrinth_season_reward_group unavailable, season rewards disabled: %v", err)
|
||||
} else {
|
||||
seasonMilestones = buildLabyrinthSeasonMilestones(seasonRows, seasonRewardRows, itemsByRewardGroup)
|
||||
}
|
||||
|
||||
return clearRewards, accumTiers, seasonMilestones
|
||||
}
|
||||
|
||||
func buildLabyrinthSeasonMilestones(
|
||||
seasonRows []EntityMEventQuestLabyrinthSeason,
|
||||
seasonRewardRows []EntityMEventQuestLabyrinthSeasonRewardGroup,
|
||||
itemsByRewardGroup map[int32][]RewardItem,
|
||||
) map[int32][]LabyrinthSeasonMilestone {
|
||||
// chapter -> SeasonRewardGroupId (all seasons of a chapter share one)
|
||||
groupByChapter := make(map[int32]int32)
|
||||
for _, r := range seasonRows {
|
||||
groupByChapter[r.EventQuestChapterId] = r.SeasonRewardGroupId
|
||||
}
|
||||
// SeasonRewardGroupId -> its rows, in table order
|
||||
rowsByGroup := make(map[int32][]EntityMEventQuestLabyrinthSeasonRewardGroup)
|
||||
for _, r := range seasonRewardRows {
|
||||
rowsByGroup[r.EventQuestLabyrinthSeasonRewardGroupId] = append(rowsByGroup[r.EventQuestLabyrinthSeasonRewardGroupId], r)
|
||||
}
|
||||
|
||||
milestones := make(map[int32][]LabyrinthSeasonMilestone)
|
||||
for chapterId, seasonGroupId := range groupByChapter {
|
||||
rows := rowsByGroup[seasonGroupId]
|
||||
if len(rows) == 0 {
|
||||
continue
|
||||
}
|
||||
// rank distinct reward-group ids ascending -> 1-based head stage order
|
||||
stageByRewardGroup := make(map[int32]int32)
|
||||
var distinct []int32
|
||||
for _, r := range rows {
|
||||
if _, seen := stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId]; !seen {
|
||||
stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId] = 0
|
||||
distinct = append(distinct, r.EventQuestLabyrinthRewardGroupId)
|
||||
}
|
||||
}
|
||||
sort.Slice(distinct, func(i, j int) bool { return distinct[i] < distinct[j] })
|
||||
for i, gid := range distinct {
|
||||
stageByRewardGroup[gid] = int32(i + 1)
|
||||
}
|
||||
|
||||
list := make([]LabyrinthSeasonMilestone, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
list = append(list, LabyrinthSeasonMilestone{
|
||||
HeadQuestId: r.HeadQuestId,
|
||||
HeadStageOrder: stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
||||
Rewards: itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
||||
})
|
||||
}
|
||||
milestones[chapterId] = list
|
||||
}
|
||||
return milestones
|
||||
}
|
||||
Reference in New Issue
Block a user