Files
Genarrative/docs/technical/PUZZLE_FAILURE_EXTENSION_AND_SAVE_ARCHIVE_2026-05-01.md
2026-05-01 20:29:09 +08:00

5.2 KiB
Raw Blame History

拼图失败续时与存档投影设计 2026-05-01

背景

拼图运行时已经有倒计时失败态、道具确认扣费、下一关推荐和个人存档页,但失败后的玩家选择与拼图作品存档投影还没有闭环:

  1. 倒计时结束后只能返回,不能重新开始或付费继续。
  2. 进入拼图作品后,存档页没有稳定出现一条可恢复的拼图游戏存档。
  3. 每通过一关后,存档应该更新到下一关入口,而不是停留在旧关卡。

本轮只补齐拼图运行态与存档投影,不迁移旧 server-node,不新增平行存档页。

目标

  1. 限定时间内未完成时弹出失败面板。
  2. 失败面板提供两个选择:
    • 重新开始:重新开启当前拼图关卡,不扣光点。
    • 继续1分钟:先弹出确认窗口,确认后消耗 1 光点,并把当前失败关卡恢复为 playing,剩余时间固定为 60000ms
  3. 进入拼图作品后立即写入 profile_save_archive,存档页显示拼图存档。
  4. 每次进入下一关后更新同一条拼图存档,使存档恢复时指向最新可继续的关卡。

运行态规则

失败续时

PuzzleRuntimePropKind 增加 extendTime,沿用现有道具确认与扣费接口:

  1. 前端只在 runtimeStatus = failed 时开放 继续1分钟
  2. 点击后打开独立确认弹窗,文案只显示短标题和 消耗 1 光点
  3. 正式 run 继续走 POST /api/runtime/puzzle/runs/:runId/props
  4. api-serverextendTime 映射为账单 asset_kind = puzzle_prop_extend_time
  5. SpacetimeDB 侧只允许失败关卡续时;续时成功后:
    • status = playing
    • remaining_ms = 60000
    • elapsed_ms = None
    • cleared_at_ms = None
    • 清空暂停与冻结生效点
    • 调整 paused_accumulated_ms,保证从确认成功那一刻开始完整倒计时 60

本地调试 run 没有真实钱包,沿用本地道具兜底:仍弹确认窗,但不扣真实光点。

重新开始

重新开始不复用旧失败棋盘,而是重新创建当前关卡的 run

  1. 前端从当前 currentLevel.profileIdcurrentLevel.levelId 调用 startPuzzleRun
  2. 新 run 的棋盘重新打乱、倒计时重置。
  3. 如果当前关卡来自作品内部第 N 关,必须携带 levelId,避免重开误回作品第 1 关。
  4. 旧失败 run 保留为历史运行记录,不在前端继续使用。

为支持第 3 点,PuzzleRuntimeLevelSnapshot 增加 levelId: string | null

存档投影规则

复用现有 profile_save_archive 表,不新增拼图专属存档表。拼图存档固定规则:

  1. world_key = puzzle:{entry_profile_id}
  2. world_type = PUZZLE
  3. profile_id = entry_profile_id,保证同一个作品链只覆盖一条存档。
  4. world_name 使用当前可恢复关卡名。
  5. subtitle 使用 第 N 关
  6. summary_text 使用可恢复关卡状态:
    • playing拼图进行中
    • failed关卡失败
    • cleared关卡已完成
  7. cover_image_src 使用可恢复关卡正式图。
  8. game_state_json 保存最小拼图恢复载荷:
    • runtimeKind = "puzzle"
    • runId
    • entryProfileId
    • currentProfileId
    • currentLevelIndex
    • currentLevelId
    • status

通关存档投影有一个额外规则:如果当前关卡已通关,并且 refresh_next_level_handoff 已经确认同作品存在下一关,则存档立即投影到同作品下一关入口,status 写为 playingsubtitle / world_name / cover_image_src / currentLevelId 都使用下一关。若当前作品没有下一关、只存在相似作品候选,存档保持当前已通关关卡,等待玩家在结算弹窗里选择相似作品,不能提前替玩家切换到某个候选作品。

写入时机

SpacetimeDB 拼图运行态每次持久化 run 时同步刷新存档:

  1. start_puzzle_run:创建 run 后立即写入拼图存档。
  2. advance_puzzle_next_level:进入下一关后更新同一条存档。
  3. use_puzzle_runtime_prop(extendTime):续时成功后更新状态。
  4. get_puzzle_run 导致失败态落库时,也同步更新为失败存档。
  5. submit_puzzle_leaderboard_entry:正式 run 提交成绩并把当前关标记为已通关时,先刷新下一关 handoff再按上面的通关投影规则同步存档。

前端在 startPuzzleRun / usePuzzleProp / submitPuzzleLeaderboard / advancePuzzleLevel / getPuzzleRun 成功后主动刷新存档列表,避免存档页停留在进入作品前或上一关的旧投影。

验收

  1. 倒计时归零后失败弹窗有 重新开始继续1分钟
  2. 点击 继续1分钟 后先出现扣费确认,确认成功后失败弹窗关闭并恢复 60 秒倒计时。
  3. 光点余额不足时确认弹窗保留,并展示错误。
  4. 点击 重新开始 后当前关卡重新打乱并重置倒计时。
  5. 进入拼图作品后,存档页出现 worldType = PUZZLE 的拼图存档。
  6. 通过一关后,只要后端确认同作品下一关存在,同一条存档立即更新到新关卡;没有同作品下一关时保留已完成关卡,等待玩家选择相似作品。
  7. 定向前端测试、Rust 拼图模块测试与编码检查通过。