Compare commits

2 Commits

Author SHA1 Message Date
Ilya Groshev cc9dc4f1c5 Fix menu pick black screen for quests without a difficulty relation
Build and Push Docker images to Docker Hub / build-and-push (push) Has been cancelled
2026-05-12 11:21:19 +03:00
Ilya Groshev 479ace5c8e Fix menu pick from replay flow returning to wrong state 2026-05-12 09:27:28 +03:00
6 changed files with 17 additions and 27 deletions
-20
View File
@@ -34,7 +34,6 @@ type QuestCatalog struct {
TutorialUnlockConditions []EntityMTutorialUnlockCondition TutorialUnlockConditions []EntityMTutorialUnlockCondition
ChapterLastSceneByQuestId map[int32]int32 ChapterLastSceneByQuestId map[int32]int32
SeasonIdByRouteId map[int32]int32 SeasonIdByRouteId map[int32]int32
QuestsWithDifficulty map[int32]bool // any questId referenced in m_quest_relation_main_flow
BattleOnlyTargetSceneByQuestId map[int32]int32 BattleOnlyTargetSceneByQuestId map[int32]int32
UserExpThresholds []int32 UserExpThresholds []int32
@@ -240,21 +239,6 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return nil, fmt.Errorf("load tutorial unlock condition table: %w", err) return nil, fmt.Errorf("load tutorial unlock condition table: %w", err)
} }
relations, err := utils.ReadTable[EntityMQuestRelationMainFlow]("m_quest_relation_main_flow")
if err != nil {
return nil, fmt.Errorf("load quest relation main flow table: %w", err)
}
questsWithDifficulty := make(map[int32]bool, len(relations)*3)
for _, r := range relations {
questsWithDifficulty[r.MainFlowQuestId] = true
if r.ReplayFlowQuestId != 0 {
questsWithDifficulty[r.ReplayFlowQuestId] = true
}
if r.SubFlowQuestId != 0 {
questsWithDifficulty[r.SubFlowQuestId] = true
}
}
battleOnlyTargetSceneByQuestId := make(map[int32]int32) battleOnlyTargetSceneByQuestId := make(map[int32]int32)
for _, scene := range scenes { for _, scene := range scenes {
if scene.IsBattleOnlyTarget { if scene.IsBattleOnlyTarget {
@@ -555,7 +539,6 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
TutorialUnlockConditions: tutorialUnlockConds, TutorialUnlockConditions: tutorialUnlockConds,
ChapterLastSceneByQuestId: chapterLastSceneByQuestId, ChapterLastSceneByQuestId: chapterLastSceneByQuestId,
SeasonIdByRouteId: seasonIdByRouteId, SeasonIdByRouteId: seasonIdByRouteId,
QuestsWithDifficulty: questsWithDifficulty,
BattleOnlyTargetSceneByQuestId: battleOnlyTargetSceneByQuestId, BattleOnlyTargetSceneByQuestId: battleOnlyTargetSceneByQuestId,
UserExpThresholds: BuildExpThresholds(paramMapRows, 1), UserExpThresholds: BuildExpThresholds(paramMapRows, 1),
@@ -579,6 +562,3 @@ func (q *QuestCatalog) BattleOnlyTargetSceneIdFor(questId int32) (int32, bool) {
return v, ok return v, ok
} }
func (q *QuestCatalog) QuestHasDifficulty(questId int32) bool {
return q.QuestsWithDifficulty[questId]
}
+5 -3
View File
@@ -62,7 +62,7 @@ func (h *QuestHandler) handleQuestStartInternal(user *store.UserState, questId i
questState.UserDeckNumber = userDeckNumber questState.UserDeckNumber = userDeckNumber
isCleared := questState.QuestStateType == model.UserQuestStateTypeCleared isCleared := questState.QuestStateType == model.UserQuestStateTypeCleared
isMenuPick := !isReplayFlow && !isMainFlow && (isCleared || h.QuestHasDifficulty(questId)) isMenuPick := !isReplayFlow && !isMainFlow
switch { switch {
case isMenuPick: case isMenuPick:
@@ -122,6 +122,7 @@ func snapshotMainQuestIfNeeded(user *store.UserState) {
MainQuestSeasonId: user.MainQuest.MainQuestSeasonId, MainQuestSeasonId: user.MainQuest.MainQuestSeasonId,
IsReachedLastQuestScene: user.MainQuest.IsReachedLastQuestScene, IsReachedLastQuestScene: user.MainQuest.IsReachedLastQuestScene,
PortalCageInProgress: user.PortalCageStatus.IsCurrentProgress, PortalCageInProgress: user.PortalCageStatus.IsCurrentProgress,
CurrentQuestFlowType: user.MainQuest.CurrentQuestFlowType,
} }
} }
@@ -270,13 +271,14 @@ func (h *QuestHandler) HandleQuestFinish(user *store.UserState, questId int32, i
user.MainQuest.CurrentMainQuestRouteId = ctx.CurrentMainQuestRouteId user.MainQuest.CurrentMainQuestRouteId = ctx.CurrentMainQuestRouteId
user.MainQuest.MainQuestSeasonId = ctx.MainQuestSeasonId user.MainQuest.MainQuestSeasonId = ctx.MainQuestSeasonId
user.MainQuest.IsReachedLastQuestScene = ctx.IsReachedLastQuestScene user.MainQuest.IsReachedLastQuestScene = ctx.IsReachedLastQuestScene
user.MainQuest.CurrentQuestFlowType = ctx.CurrentQuestFlowType
user.PortalCageStatus.IsCurrentProgress = ctx.PortalCageInProgress user.PortalCageStatus.IsCurrentProgress = ctx.PortalCageInProgress
user.PortalCageStatus.LatestVersion = nowMillis user.PortalCageStatus.LatestVersion = nowMillis
user.MainQuest.SavedContext = store.SavedQuestContext{} user.MainQuest.SavedContext = store.SavedQuestContext{}
user.MainQuest.LatestVersion = nowMillis user.MainQuest.LatestVersion = nowMillis
log.Printf("[HandleQuestFinish] restored snapshot for quest %d (route=%d season=%d scene=%d head=%d cage=%v)", log.Printf("[HandleQuestFinish] restored snapshot for quest %d (route=%d season=%d scene=%d head=%d cage=%v flow=%d)",
questId, ctx.CurrentMainQuestRouteId, ctx.MainQuestSeasonId, questId, ctx.CurrentMainQuestRouteId, ctx.MainQuestSeasonId,
ctx.CurrentQuestSceneId, ctx.HeadQuestSceneId, ctx.PortalCageInProgress) ctx.CurrentQuestSceneId, ctx.HeadQuestSceneId, ctx.PortalCageInProgress, ctx.CurrentQuestFlowType)
} }
h.clearQuestMissions(user, questId, nowMillis) h.clearQuestMissions(user, questId, nowMillis)
+2 -2
View File
@@ -131,7 +131,7 @@ func load1to1(db *sql.DB, uid int64, u *store.UserState) {
progress_quest_flow_type, main_quest_season_id, latest_version, progress_quest_flow_type, main_quest_season_id, latest_version,
saved_ctx_active, saved_ctx_current_quest_scene_id, saved_ctx_head_quest_scene_id, saved_ctx_active, saved_ctx_current_quest_scene_id, saved_ctx_head_quest_scene_id,
saved_ctx_current_main_quest_route_id, saved_ctx_main_quest_season_id, saved_ctx_current_main_quest_route_id, saved_ctx_main_quest_season_id,
saved_ctx_is_reached_last_quest_scene, saved_ctx_portal_cage_in_progress, saved_ctx_is_reached_last_quest_scene, saved_ctx_portal_cage_in_progress, saved_ctx_current_quest_flow_type,
replay_flow_current_quest_scene_id, replay_flow_head_quest_scene_id replay_flow_current_quest_scene_id, replay_flow_head_quest_scene_id
FROM user_main_quest WHERE user_id=?`, uid). FROM user_main_quest WHERE user_id=?`, uid).
Scan(&u.MainQuest.CurrentQuestFlowType, &u.MainQuest.CurrentMainQuestRouteId, &u.MainQuest.CurrentQuestSceneId, Scan(&u.MainQuest.CurrentQuestFlowType, &u.MainQuest.CurrentMainQuestRouteId, &u.MainQuest.CurrentQuestSceneId,
@@ -139,7 +139,7 @@ func load1to1(db *sql.DB, uid int64, u *store.UserState) {
&u.MainQuest.ProgressQuestFlowType, &u.MainQuest.MainQuestSeasonId, &u.MainQuest.LatestVersion, &u.MainQuest.ProgressQuestFlowType, &u.MainQuest.MainQuestSeasonId, &u.MainQuest.LatestVersion,
&ctxActive, &u.MainQuest.SavedContext.CurrentQuestSceneId, &u.MainQuest.SavedContext.HeadQuestSceneId, &ctxActive, &u.MainQuest.SavedContext.CurrentQuestSceneId, &u.MainQuest.SavedContext.HeadQuestSceneId,
&u.MainQuest.SavedContext.CurrentMainQuestRouteId, &u.MainQuest.SavedContext.MainQuestSeasonId, &u.MainQuest.SavedContext.CurrentMainQuestRouteId, &u.MainQuest.SavedContext.MainQuestSeasonId,
&ctxIsLast, &ctxCage, &ctxIsLast, &ctxCage, &u.MainQuest.SavedContext.CurrentQuestFlowType,
&u.MainQuest.ReplayFlowCurrentQuestSceneId, &u.MainQuest.ReplayFlowHeadQuestSceneId) &u.MainQuest.ReplayFlowCurrentQuestSceneId, &u.MainQuest.ReplayFlowHeadQuestSceneId)
u.MainQuest.IsReachedLastQuestScene = b != 0 u.MainQuest.IsReachedLastQuestScene = b != 0
u.MainQuest.SavedContext.Active = ctxActive != 0 u.MainQuest.SavedContext.Active = ctxActive != 0
+4 -2
View File
@@ -49,7 +49,7 @@ func writeUserState(tx *sql.Tx, uid int64, u *store.UserState) error {
u.LoginBonus.LatestRewardReceiveDatetime, u.LoginBonus.LatestVersion); err != nil { u.LoginBonus.LatestRewardReceiveDatetime, u.LoginBonus.LatestVersion); err != nil {
return err return err
} }
if err := exec(`INSERT INTO user_main_quest (user_id, current_quest_flow_type, current_main_quest_route_id, current_quest_scene_id, head_quest_scene_id, is_reached_last_quest_scene, progress_quest_scene_id, progress_head_quest_scene_id, progress_quest_flow_type, main_quest_season_id, latest_version, saved_ctx_active, saved_ctx_current_quest_scene_id, saved_ctx_head_quest_scene_id, saved_ctx_current_main_quest_route_id, saved_ctx_main_quest_season_id, saved_ctx_is_reached_last_quest_scene, saved_ctx_portal_cage_in_progress, replay_flow_current_quest_scene_id, replay_flow_head_quest_scene_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`, if err := exec(`INSERT INTO user_main_quest (user_id, current_quest_flow_type, current_main_quest_route_id, current_quest_scene_id, head_quest_scene_id, is_reached_last_quest_scene, progress_quest_scene_id, progress_head_quest_scene_id, progress_quest_flow_type, main_quest_season_id, latest_version, saved_ctx_active, saved_ctx_current_quest_scene_id, saved_ctx_head_quest_scene_id, saved_ctx_current_main_quest_route_id, saved_ctx_main_quest_season_id, saved_ctx_is_reached_last_quest_scene, saved_ctx_portal_cage_in_progress, saved_ctx_current_quest_flow_type, replay_flow_current_quest_scene_id, replay_flow_head_quest_scene_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
uid, u.MainQuest.CurrentQuestFlowType, u.MainQuest.CurrentMainQuestRouteId, u.MainQuest.CurrentQuestSceneId, uid, u.MainQuest.CurrentQuestFlowType, u.MainQuest.CurrentMainQuestRouteId, u.MainQuest.CurrentQuestSceneId,
u.MainQuest.HeadQuestSceneId, boolToInt(u.MainQuest.IsReachedLastQuestScene), u.MainQuest.ProgressQuestSceneId, u.MainQuest.HeadQuestSceneId, boolToInt(u.MainQuest.IsReachedLastQuestScene), u.MainQuest.ProgressQuestSceneId,
u.MainQuest.ProgressHeadQuestSceneId, u.MainQuest.ProgressQuestFlowType, u.MainQuest.MainQuestSeasonId, u.MainQuest.ProgressHeadQuestSceneId, u.MainQuest.ProgressQuestFlowType, u.MainQuest.MainQuestSeasonId,
@@ -59,6 +59,7 @@ func writeUserState(tx *sql.Tx, uid int64, u *store.UserState) error {
u.MainQuest.SavedContext.CurrentMainQuestRouteId, u.MainQuest.SavedContext.MainQuestSeasonId, u.MainQuest.SavedContext.CurrentMainQuestRouteId, u.MainQuest.SavedContext.MainQuestSeasonId,
boolToInt(u.MainQuest.SavedContext.IsReachedLastQuestScene), boolToInt(u.MainQuest.SavedContext.IsReachedLastQuestScene),
boolToInt(u.MainQuest.SavedContext.PortalCageInProgress), boolToInt(u.MainQuest.SavedContext.PortalCageInProgress),
u.MainQuest.SavedContext.CurrentQuestFlowType,
u.MainQuest.ReplayFlowCurrentQuestSceneId, u.MainQuest.ReplayFlowHeadQuestSceneId); err != nil { u.MainQuest.ReplayFlowCurrentQuestSceneId, u.MainQuest.ReplayFlowHeadQuestSceneId); err != nil {
return err return err
} }
@@ -566,7 +567,7 @@ func diffAndSave(tx *sql.Tx, uid int64, before, after *store.UserState) error {
} }
} }
if before.MainQuest != after.MainQuest { if before.MainQuest != after.MainQuest {
if err := exec(`UPDATE user_main_quest SET current_quest_flow_type=?, current_main_quest_route_id=?, current_quest_scene_id=?, head_quest_scene_id=?, is_reached_last_quest_scene=?, progress_quest_scene_id=?, progress_head_quest_scene_id=?, progress_quest_flow_type=?, main_quest_season_id=?, latest_version=?, saved_ctx_active=?, saved_ctx_current_quest_scene_id=?, saved_ctx_head_quest_scene_id=?, saved_ctx_current_main_quest_route_id=?, saved_ctx_main_quest_season_id=?, saved_ctx_is_reached_last_quest_scene=?, saved_ctx_portal_cage_in_progress=?, replay_flow_current_quest_scene_id=?, replay_flow_head_quest_scene_id=? WHERE user_id=?`, if err := exec(`UPDATE user_main_quest SET current_quest_flow_type=?, current_main_quest_route_id=?, current_quest_scene_id=?, head_quest_scene_id=?, is_reached_last_quest_scene=?, progress_quest_scene_id=?, progress_head_quest_scene_id=?, progress_quest_flow_type=?, main_quest_season_id=?, latest_version=?, saved_ctx_active=?, saved_ctx_current_quest_scene_id=?, saved_ctx_head_quest_scene_id=?, saved_ctx_current_main_quest_route_id=?, saved_ctx_main_quest_season_id=?, saved_ctx_is_reached_last_quest_scene=?, saved_ctx_portal_cage_in_progress=?, saved_ctx_current_quest_flow_type=?, replay_flow_current_quest_scene_id=?, replay_flow_head_quest_scene_id=? WHERE user_id=?`,
after.MainQuest.CurrentQuestFlowType, after.MainQuest.CurrentMainQuestRouteId, after.MainQuest.CurrentQuestSceneId, after.MainQuest.CurrentQuestFlowType, after.MainQuest.CurrentMainQuestRouteId, after.MainQuest.CurrentQuestSceneId,
after.MainQuest.HeadQuestSceneId, boolToInt(after.MainQuest.IsReachedLastQuestScene), after.MainQuest.ProgressQuestSceneId, after.MainQuest.HeadQuestSceneId, boolToInt(after.MainQuest.IsReachedLastQuestScene), after.MainQuest.ProgressQuestSceneId,
after.MainQuest.ProgressHeadQuestSceneId, after.MainQuest.ProgressQuestFlowType, after.MainQuest.MainQuestSeasonId, after.MainQuest.ProgressHeadQuestSceneId, after.MainQuest.ProgressQuestFlowType, after.MainQuest.MainQuestSeasonId,
@@ -576,6 +577,7 @@ func diffAndSave(tx *sql.Tx, uid int64, before, after *store.UserState) error {
after.MainQuest.SavedContext.CurrentMainQuestRouteId, after.MainQuest.SavedContext.MainQuestSeasonId, after.MainQuest.SavedContext.CurrentMainQuestRouteId, after.MainQuest.SavedContext.MainQuestSeasonId,
boolToInt(after.MainQuest.SavedContext.IsReachedLastQuestScene), boolToInt(after.MainQuest.SavedContext.IsReachedLastQuestScene),
boolToInt(after.MainQuest.SavedContext.PortalCageInProgress), boolToInt(after.MainQuest.SavedContext.PortalCageInProgress),
after.MainQuest.SavedContext.CurrentQuestFlowType,
after.MainQuest.ReplayFlowCurrentQuestSceneId, after.MainQuest.ReplayFlowHeadQuestSceneId, uid); err != nil { after.MainQuest.ReplayFlowCurrentQuestSceneId, after.MainQuest.ReplayFlowHeadQuestSceneId, uid); err != nil {
return err return err
} }
+1
View File
@@ -530,6 +530,7 @@ type SavedQuestContext struct {
MainQuestSeasonId int32 MainQuestSeasonId int32
IsReachedLastQuestScene bool IsReachedLastQuestScene bool
PortalCageInProgress bool PortalCageInProgress bool
CurrentQuestFlowType int32
} }
type EventQuestState struct { type EventQuestState struct {
@@ -0,0 +1,5 @@
-- +goose Up
ALTER TABLE user_main_quest ADD COLUMN saved_ctx_current_quest_flow_type INTEGER NOT NULL DEFAULT 0;
-- +goose Down
ALTER TABLE user_main_quest DROP COLUMN saved_ctx_current_quest_flow_type;