mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 05:43:41 +03:00
Implement Tower accumulation reward claiming
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
package masterdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"lunar-tear/server/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TowerTier struct {
|
||||||
|
QuestMissionClearCount int32
|
||||||
|
Rewards []RewardItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type TowerCatalog struct {
|
||||||
|
TiersByChapter map[int32][]TowerTier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TowerCatalog) CollectRewards(chapterId, oldCount, targetCount int32) ([]RewardItem, int32) {
|
||||||
|
var items []RewardItem
|
||||||
|
highest := int32(0)
|
||||||
|
for _, t := range c.TiersByChapter[chapterId] {
|
||||||
|
if t.QuestMissionClearCount > oldCount && t.QuestMissionClearCount <= targetCount {
|
||||||
|
items = append(items, t.Rewards...)
|
||||||
|
if t.QuestMissionClearCount > highest {
|
||||||
|
highest = t.QuestMissionClearCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items, highest
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadTowerCatalog() *TowerCatalog {
|
||||||
|
// chapterId -> accumulation reward group id
|
||||||
|
accumRewardRows, err := utils.ReadTable[EntityMEventQuestTowerAccumulationReward]("m_event_quest_tower_accumulation_reward")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("load event quest tower accumulation reward table: %v", err)
|
||||||
|
}
|
||||||
|
groupByChapter := make(map[int32]int32, len(accumRewardRows))
|
||||||
|
for _, r := range accumRewardRows {
|
||||||
|
groupByChapter[r.EventQuestChapterId] = r.EventQuestTowerAccumulationRewardGroupId
|
||||||
|
}
|
||||||
|
|
||||||
|
// reward group id -> reward items
|
||||||
|
rewardGroupRows, err := utils.ReadTable[EntityMEventQuestTowerRewardGroup]("m_event_quest_tower_reward_group")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("load event quest tower reward group table: %v", err)
|
||||||
|
}
|
||||||
|
itemsByRewardGroup := make(map[int32][]RewardItem)
|
||||||
|
for _, r := range rewardGroupRows {
|
||||||
|
itemsByRewardGroup[r.EventQuestTowerRewardGroupId] = append(itemsByRewardGroup[r.EventQuestTowerRewardGroupId], RewardItem{
|
||||||
|
PossessionType: r.PossessionType,
|
||||||
|
PossessionId: r.PossessionId,
|
||||||
|
Count: r.Count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// accumulation group id -> tiers (threshold + resolved reward items)
|
||||||
|
accumGroupRows, err := utils.ReadTable[EntityMEventQuestTowerAccumulationRewardGroup]("m_event_quest_tower_accumulation_reward_group")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("load event quest tower accumulation reward group table: %v", err)
|
||||||
|
}
|
||||||
|
tiersByGroup := make(map[int32][]TowerTier)
|
||||||
|
for _, r := range accumGroupRows {
|
||||||
|
tiersByGroup[r.EventQuestTowerAccumulationRewardGroupId] = append(tiersByGroup[r.EventQuestTowerAccumulationRewardGroupId], TowerTier{
|
||||||
|
QuestMissionClearCount: r.QuestMissionClearCount,
|
||||||
|
Rewards: itemsByRewardGroup[r.EventQuestTowerRewardGroupId],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve per-chapter, sorted ascending by threshold
|
||||||
|
tiersByChapter := make(map[int32][]TowerTier, len(groupByChapter))
|
||||||
|
for chapterId, groupId := range groupByChapter {
|
||||||
|
tiers := tiersByGroup[groupId]
|
||||||
|
sort.Slice(tiers, func(i, j int) bool {
|
||||||
|
return tiers[i].QuestMissionClearCount < tiers[j].QuestMissionClearCount
|
||||||
|
})
|
||||||
|
tiersByChapter[chapterId] = tiers
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("tower catalog loaded: %d chapters", len(tiersByChapter))
|
||||||
|
|
||||||
|
return &TowerCatalog{TiersByChapter: tiersByChapter}
|
||||||
|
}
|
||||||
@@ -139,6 +139,8 @@ func buildCatalogs() (*Catalogs, error) {
|
|||||||
|
|
||||||
bigHuntCatalog := masterdata.LoadBigHuntCatalog()
|
bigHuntCatalog := masterdata.LoadBigHuntCatalog()
|
||||||
|
|
||||||
|
towerCatalog := masterdata.LoadTowerCatalog()
|
||||||
|
|
||||||
return &Catalogs{
|
return &Catalogs{
|
||||||
GameConfig: gameConfig,
|
GameConfig: gameConfig,
|
||||||
Parts: partsCatalog,
|
Parts: partsCatalog,
|
||||||
@@ -164,6 +166,7 @@ func buildCatalogs() (*Catalogs, error) {
|
|||||||
Companion: companionCatalog,
|
Companion: companionCatalog,
|
||||||
SideStory: sideStoryCatalog,
|
SideStory: sideStoryCatalog,
|
||||||
BigHunt: bigHuntCatalog,
|
BigHunt: bigHuntCatalog,
|
||||||
|
Tower: towerCatalog,
|
||||||
QuestHandler: questHandler,
|
QuestHandler: questHandler,
|
||||||
GachaHandler: gachaHandler,
|
GachaHandler: gachaHandler,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ type Catalogs struct {
|
|||||||
Companion *masterdata.CompanionCatalog
|
Companion *masterdata.CompanionCatalog
|
||||||
SideStory *masterdata.SideStoryCatalog
|
SideStory *masterdata.SideStoryCatalog
|
||||||
BigHunt *masterdata.BigHuntCatalog
|
BigHunt *masterdata.BigHuntCatalog
|
||||||
|
Tower *masterdata.TowerCatalog
|
||||||
|
|
||||||
// Catalog-derived handlers must rebuild on every reload because they
|
// Catalog-derived handlers must rebuild on every reload because they
|
||||||
// embed/cache pointers to specific catalog instances.
|
// embed/cache pointers to specific catalog instances.
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
pb "lunar-tear/server/gen/proto"
|
||||||
|
"lunar-tear/server/internal/gametime"
|
||||||
|
"lunar-tear/server/internal/model"
|
||||||
|
"lunar-tear/server/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *QuestServiceServer) ReceiveTowerAccumulationReward(ctx context.Context, req *pb.ReceiveTowerAccumulationRewardRequest) (*pb.ReceiveTowerAccumulationRewardResponse, error) {
|
||||||
|
log.Printf("[QuestService] ReceiveTowerAccumulationReward: eventQuestChapterId=%d targetMissionClearCount=%d",
|
||||||
|
req.EventQuestChapterId, req.TargetMissionClearCount)
|
||||||
|
|
||||||
|
cat := s.holder.Get()
|
||||||
|
tower := cat.Tower
|
||||||
|
granter := cat.QuestHandler.Granter
|
||||||
|
|
||||||
|
userId := CurrentUserId(ctx, s.users, s.sessions)
|
||||||
|
nowMillis := gametime.NowMillis()
|
||||||
|
|
||||||
|
s.users.UpdateUser(userId, func(user *store.UserState) {
|
||||||
|
rec := user.TowerAccumulationRewards[req.EventQuestChapterId]
|
||||||
|
old := rec.LatestRewardReceiveQuestMissionClearCount
|
||||||
|
|
||||||
|
items, highest := tower.CollectRewards(req.EventQuestChapterId, old, req.TargetMissionClearCount)
|
||||||
|
if highest <= old {
|
||||||
|
log.Printf("[QuestService] ReceiveTowerAccumulationReward: nothing to grant for chapter=%d (claimed=%d, target=%d)",
|
||||||
|
req.EventQuestChapterId, old, req.TargetMissionClearCount)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, it := range items {
|
||||||
|
granter.GrantFull(user, model.PossessionType(it.PossessionType), it.PossessionId, it.Count, nowMillis)
|
||||||
|
}
|
||||||
|
|
||||||
|
rec.EventQuestChapterId = req.EventQuestChapterId
|
||||||
|
rec.LatestRewardReceiveQuestMissionClearCount = highest
|
||||||
|
rec.LatestVersion = nowMillis
|
||||||
|
user.TowerAccumulationRewards[req.EventQuestChapterId] = rec
|
||||||
|
|
||||||
|
log.Printf("[QuestService] ReceiveTowerAccumulationReward: chapter=%d granted %d item(s), claimed %d -> %d",
|
||||||
|
req.EventQuestChapterId, len(items), old, highest)
|
||||||
|
})
|
||||||
|
|
||||||
|
return &pb.ReceiveTowerAccumulationRewardResponse{}, nil
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ func CloneUserState(u UserState) UserState {
|
|||||||
Unlocks: maps.Clone(u.Gimmick.Unlocks),
|
Unlocks: maps.Clone(u.Gimmick.Unlocks),
|
||||||
}
|
}
|
||||||
out.CageOrnamentRewards = maps.Clone(u.CageOrnamentRewards)
|
out.CageOrnamentRewards = maps.Clone(u.CageOrnamentRewards)
|
||||||
|
out.TowerAccumulationRewards = maps.Clone(u.TowerAccumulationRewards)
|
||||||
out.ConsumableItems = maps.Clone(u.ConsumableItems)
|
out.ConsumableItems = maps.Clone(u.ConsumableItems)
|
||||||
out.Materials = maps.Clone(u.Materials)
|
out.Materials = maps.Clone(u.Materials)
|
||||||
out.Parts = maps.Clone(u.Parts)
|
out.Parts = maps.Clone(u.Parts)
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ func SeedUserState(userId int64, uuid string, nowMillis int64, platform model.Cl
|
|||||||
Unlocks: make(map[GimmickKey]GimmickUnlockState),
|
Unlocks: make(map[GimmickKey]GimmickUnlockState),
|
||||||
},
|
},
|
||||||
CageOrnamentRewards: make(map[int32]CageOrnamentRewardState),
|
CageOrnamentRewards: make(map[int32]CageOrnamentRewardState),
|
||||||
|
TowerAccumulationRewards: make(map[int32]TowerAccumulationRewardState),
|
||||||
ConsumableItems: make(map[int32]int32),
|
ConsumableItems: make(map[int32]int32),
|
||||||
Materials: make(map[int32]int32),
|
Materials: make(map[int32]int32),
|
||||||
Thoughts: make(map[string]ThoughtState),
|
Thoughts: make(map[string]ThoughtState),
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ func initMaps(u *store.UserState) {
|
|||||||
u.ShopReplaceableLineup = make(map[int32]store.UserShopReplaceableLineupState)
|
u.ShopReplaceableLineup = make(map[int32]store.UserShopReplaceableLineupState)
|
||||||
u.ExploreScores = make(map[int32]store.ExploreScoreState)
|
u.ExploreScores = make(map[int32]store.ExploreScoreState)
|
||||||
u.CageOrnamentRewards = make(map[int32]store.CageOrnamentRewardState)
|
u.CageOrnamentRewards = make(map[int32]store.CageOrnamentRewardState)
|
||||||
|
u.TowerAccumulationRewards = make(map[int32]store.TowerAccumulationRewardState)
|
||||||
u.CharacterBoards = make(map[int32]store.CharacterBoardState)
|
u.CharacterBoards = make(map[int32]store.CharacterBoardState)
|
||||||
u.CharacterBoardAbilities = make(map[store.CharacterBoardAbilityKey]store.CharacterBoardAbilityState)
|
u.CharacterBoardAbilities = make(map[store.CharacterBoardAbilityKey]store.CharacterBoardAbilityState)
|
||||||
u.CharacterBoardStatusUps = make(map[store.CharacterBoardStatusUpKey]store.CharacterBoardStatusUpState)
|
u.CharacterBoardStatusUps = make(map[store.CharacterBoardStatusUpKey]store.CharacterBoardStatusUpState)
|
||||||
@@ -651,6 +652,13 @@ func loadMapTables(db *sql.DB, uid int64, u *store.UserState) {
|
|||||||
u.CageOrnamentRewards[v.CageOrnamentId] = v
|
u.CageOrnamentRewards[v.CageOrnamentId] = v
|
||||||
})
|
})
|
||||||
|
|
||||||
|
queryRows(db, `SELECT event_quest_chapter_id, latest_reward_receive_quest_mission_clear_count, latest_version
|
||||||
|
FROM user_event_quest_tower_accumulation_rewards WHERE user_id=?`, uid, func(rows *sql.Rows) {
|
||||||
|
var v store.TowerAccumulationRewardState
|
||||||
|
rows.Scan(&v.EventQuestChapterId, &v.LatestRewardReceiveQuestMissionClearCount, &v.LatestVersion)
|
||||||
|
u.TowerAccumulationRewards[v.EventQuestChapterId] = v
|
||||||
|
})
|
||||||
|
|
||||||
queryRows(db, `SELECT shop_item_id, bought_count, latest_bought_count_changed_datetime, latest_version
|
queryRows(db, `SELECT shop_item_id, bought_count, latest_bought_count_changed_datetime, latest_version
|
||||||
FROM user_shop_items WHERE user_id=?`, uid, func(rows *sql.Rows) {
|
FROM user_shop_items WHERE user_id=?`, uid, func(rows *sql.Rows) {
|
||||||
var v store.UserShopItemState
|
var v store.UserShopItemState
|
||||||
|
|||||||
@@ -454,6 +454,12 @@ func writeUserState(tx *sql.Tx, uid int64, u *store.UserState) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, v := range u.TowerAccumulationRewards {
|
||||||
|
if err := exec(`INSERT INTO user_event_quest_tower_accumulation_rewards (user_id, event_quest_chapter_id, latest_reward_receive_quest_mission_clear_count, latest_version) VALUES (?,?,?,?)`,
|
||||||
|
uid, v.EventQuestChapterId, v.LatestRewardReceiveQuestMissionClearCount, v.LatestVersion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, v := range u.ShopItems {
|
for _, v := range u.ShopItems {
|
||||||
if err := exec(`INSERT INTO user_shop_items (user_id, shop_item_id, bought_count, latest_bought_count_changed_datetime, latest_version) VALUES (?,?,?,?,?)`,
|
if err := exec(`INSERT INTO user_shop_items (user_id, shop_item_id, bought_count, latest_bought_count_changed_datetime, latest_version) VALUES (?,?,?,?,?)`,
|
||||||
uid, v.ShopItemId, v.BoughtCount, v.LatestBoughtCountChangedDatetime, v.LatestVersion); err != nil {
|
uid, v.ShopItemId, v.BoughtCount, v.LatestBoughtCountChangedDatetime, v.LatestVersion); err != nil {
|
||||||
@@ -994,6 +1000,11 @@ func diffAndSave(tx *sql.Tx, uid int64, before, after *store.UserState) error {
|
|||||||
return []any{v.CageOrnamentId, v.AcquisitionDatetime, v.LatestVersion}
|
return []any{v.CageOrnamentId, v.AcquisitionDatetime, v.LatestVersion}
|
||||||
},
|
},
|
||||||
"cage_ornament_id, acquisition_datetime, latest_version")
|
"cage_ornament_id, acquisition_datetime, latest_version")
|
||||||
|
diffMapInt32(tx, uid, before.TowerAccumulationRewards, after.TowerAccumulationRewards, "user_event_quest_tower_accumulation_rewards", "event_quest_chapter_id",
|
||||||
|
func(v store.TowerAccumulationRewardState) []any {
|
||||||
|
return []any{v.EventQuestChapterId, v.LatestRewardReceiveQuestMissionClearCount, v.LatestVersion}
|
||||||
|
},
|
||||||
|
"event_quest_chapter_id, latest_reward_receive_quest_mission_clear_count, latest_version")
|
||||||
diffMapInt32(tx, uid, before.ShopItems, after.ShopItems, "user_shop_items", "shop_item_id",
|
diffMapInt32(tx, uid, before.ShopItems, after.ShopItems, "user_shop_items", "shop_item_id",
|
||||||
func(v store.UserShopItemState) []any {
|
func(v store.UserShopItemState) []any {
|
||||||
return []any{v.ShopItemId, v.BoughtCount, v.LatestBoughtCountChangedDatetime, v.LatestVersion}
|
return []any{v.ShopItemId, v.BoughtCount, v.LatestBoughtCountChangedDatetime, v.LatestVersion}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ func (s *SQLiteStore) ImportUser(u *store.UserState) error {
|
|||||||
|
|
||||||
// Child tables in reverse-dependency order (matches schema's goose Down).
|
// Child tables in reverse-dependency order (matches schema's goose Down).
|
||||||
childTables := []string{
|
childTables := []string{
|
||||||
|
"user_event_quest_tower_accumulation_rewards",
|
||||||
"user_cage_ornament_rewards",
|
"user_cage_ornament_rewards",
|
||||||
"user_shop_replaceable_lineup",
|
"user_shop_replaceable_lineup",
|
||||||
"user_shop_items",
|
"user_shop_items",
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ type UserState struct {
|
|||||||
WeaponStories map[int32]WeaponStoryState
|
WeaponStories map[int32]WeaponStoryState
|
||||||
Gimmick GimmickState
|
Gimmick GimmickState
|
||||||
CageOrnamentRewards map[int32]CageOrnamentRewardState
|
CageOrnamentRewards map[int32]CageOrnamentRewardState
|
||||||
|
TowerAccumulationRewards map[int32]TowerAccumulationRewardState
|
||||||
ConsumableItems map[int32]int32
|
ConsumableItems map[int32]int32
|
||||||
Materials map[int32]int32
|
Materials map[int32]int32
|
||||||
Parts map[string]PartsState
|
Parts map[string]PartsState
|
||||||
@@ -192,6 +193,9 @@ func (u *UserState) EnsureMaps() {
|
|||||||
if u.CageOrnamentRewards == nil {
|
if u.CageOrnamentRewards == nil {
|
||||||
u.CageOrnamentRewards = make(map[int32]CageOrnamentRewardState)
|
u.CageOrnamentRewards = make(map[int32]CageOrnamentRewardState)
|
||||||
}
|
}
|
||||||
|
if u.TowerAccumulationRewards == nil {
|
||||||
|
u.TowerAccumulationRewards = make(map[int32]TowerAccumulationRewardState)
|
||||||
|
}
|
||||||
if u.ConsumableItems == nil {
|
if u.ConsumableItems == nil {
|
||||||
u.ConsumableItems = make(map[int32]int32)
|
u.ConsumableItems = make(map[int32]int32)
|
||||||
}
|
}
|
||||||
@@ -868,6 +872,12 @@ type CageOrnamentRewardState struct {
|
|||||||
LatestVersion int64
|
LatestVersion int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TowerAccumulationRewardState struct {
|
||||||
|
EventQuestChapterId int32
|
||||||
|
LatestRewardReceiveQuestMissionClearCount int32
|
||||||
|
LatestVersion int64
|
||||||
|
}
|
||||||
|
|
||||||
type PartsState struct {
|
type PartsState struct {
|
||||||
UserPartsUuid string
|
UserPartsUuid string
|
||||||
PartsId int32
|
PartsId int32
|
||||||
|
|||||||
@@ -263,6 +263,9 @@ func ChangedTables(before, after *store.UserState) []string {
|
|||||||
if !mapsEqualStruct(before.CageOrnamentRewards, after.CageOrnamentRewards) {
|
if !mapsEqualStruct(before.CageOrnamentRewards, after.CageOrnamentRewards) {
|
||||||
add("IUserCageOrnamentReward")
|
add("IUserCageOrnamentReward")
|
||||||
}
|
}
|
||||||
|
if !mapsEqualStruct(before.TowerAccumulationRewards, after.TowerAccumulationRewards) {
|
||||||
|
add("IUserEventQuestTowerAccumulationReward")
|
||||||
|
}
|
||||||
|
|
||||||
if !mapsEqualStruct(before.BigHuntMaxScores, after.BigHuntMaxScores) {
|
if !mapsEqualStruct(before.BigHuntMaxScores, after.BigHuntMaxScores) {
|
||||||
add("IUserBigHuntMaxScore")
|
add("IUserBigHuntMaxScore")
|
||||||
@@ -426,6 +429,8 @@ func keyFieldsForTable(table string) []string {
|
|||||||
return []string{"userId", "userPartsPresetTagNumber"}
|
return []string{"userId", "userPartsPresetTagNumber"}
|
||||||
case "IUserCageOrnamentReward":
|
case "IUserCageOrnamentReward":
|
||||||
return []string{"userId", "cageOrnamentId"}
|
return []string{"userId", "cageOrnamentId"}
|
||||||
|
case "IUserEventQuestTowerAccumulationReward":
|
||||||
|
return []string{"userId", "eventQuestChapterId"}
|
||||||
case "IUserAutoSaleSettingDetail":
|
case "IUserAutoSaleSettingDetail":
|
||||||
return []string{"userId", "possessionAutoSaleItemType"}
|
return []string{"userId", "possessionAutoSaleItemType"}
|
||||||
case "IUserCharacterRebirth":
|
case "IUserCharacterRebirth":
|
||||||
|
|||||||
@@ -219,11 +219,32 @@ func init() {
|
|||||||
s, _ := utils.EncodeJSONMaps(records...)
|
s, _ := utils.EncodeJSONMaps(records...)
|
||||||
return s
|
return s
|
||||||
})
|
})
|
||||||
|
register("IUserEventQuestTowerAccumulationReward", func(user store.UserState) string {
|
||||||
|
if len(user.TowerAccumulationRewards) == 0 {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
ids := make([]int, 0, len(user.TowerAccumulationRewards))
|
||||||
|
for id := range user.TowerAccumulationRewards {
|
||||||
|
ids = append(ids, int(id))
|
||||||
|
}
|
||||||
|
sort.Ints(ids)
|
||||||
|
records := make([]map[string]any, 0, len(ids))
|
||||||
|
for _, id := range ids {
|
||||||
|
st := user.TowerAccumulationRewards[int32(id)]
|
||||||
|
records = append(records, map[string]any{
|
||||||
|
"userId": user.UserId,
|
||||||
|
"eventQuestChapterId": st.EventQuestChapterId,
|
||||||
|
"latestRewardReceiveQuestMissionClearCount": st.LatestRewardReceiveQuestMissionClearCount,
|
||||||
|
"latestVersion": st.LatestVersion,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
s, _ := utils.EncodeJSONMaps(records...)
|
||||||
|
return s
|
||||||
|
})
|
||||||
registerStatic(
|
registerStatic(
|
||||||
"IUserEventQuestDailyGroupCompleteReward",
|
"IUserEventQuestDailyGroupCompleteReward",
|
||||||
"IUserEventQuestLabyrinthSeason",
|
"IUserEventQuestLabyrinthSeason",
|
||||||
"IUserEventQuestLabyrinthStage",
|
"IUserEventQuestLabyrinthStage",
|
||||||
"IUserEventQuestTowerAccumulationReward",
|
|
||||||
"IUserQuestReplayFlowRewardGroup",
|
"IUserQuestReplayFlowRewardGroup",
|
||||||
"IUserQuestAutoOrbit",
|
"IUserQuestAutoOrbit",
|
||||||
"IUserQuestSceneChoice",
|
"IUserQuestSceneChoice",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE user_event_quest_tower_accumulation_rewards (
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(user_id),
|
||||||
|
event_quest_chapter_id INTEGER NOT NULL,
|
||||||
|
latest_reward_receive_quest_mission_clear_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
latest_version INTEGER NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (user_id, event_quest_chapter_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE IF EXISTS user_event_quest_tower_accumulation_rewards;
|
||||||
Reference in New Issue
Block a user