5.0 KiB
5.0 KiB
拼图运行时真实排行榜落地说明
更新时间:2026-04-27
1. 背景
当前拼图关卡结束弹窗里的排行榜数据并不是真实用户成绩。
问题根因有两层:
- 前端本地运行态
src/services/puzzle-runtime/puzzleLocalRuntime.ts在通关后会直接拼出几条演示昵称数据。 server-rs拼图运行时虽然已经预留了leaderboardEntries字段,但module-puzzle、spacetime-client、api-server还没有真实成绩表与聚合过程,因此接口层长期返回空数组。
这导致用户在结算弹窗里看到的是“看起来像真实排行榜,但实际上是本地假数据”的结果,和平台“真实用户数据”要求冲突。
2. 本次目标
本次改动只解决一个明确问题:
- 拼图关卡结束后的排行榜必须使用真实用户成绩。
- 删除现有前端演示昵称、演示耗时等假数据。
- 不在 UI 中默认塞入任何说明型占位文案。
3. 本次落地边界
为了控制改动范围,本次不把整套拼图运行态全部迁回后端,而是在当前“本地棋盘运行态”基础上补一条真实成绩回写链路:
- 拼图拖拽、交换、合并、拆分、通关判定,仍然沿用当前本地运行态。
- 玩家一旦通关,前端立即把当前关卡成绩提交到
server-rs。 server-rs将成绩写入SpacetimeDB成绩表,并返回该关卡的真实排行榜。- 结算弹窗只展示后端返回的真实成绩榜单,不再混入本地演示数据。
这意味着:
- 这次不是“完整后端裁决化”。
- 这次是“先把排行榜真相源收回后端”,满足真实成绩展示要求。
4. 成绩真相源设计
新增拼图成绩表,按“关卡作品 + 网格规格 + 用户”维护最佳成绩。
正式开始拼图关卡时还必须同步用户玩过作品明细:
- 作品自身统计继续更新
puzzle_work_profile.play_count。 - 已登录用户写入
profile_played_world,world_key = puzzle:{profile_id}。 profile_id保存拼图作品号,world_type = PUZZLE。world_title使用关卡名,world_subtitle使用作品摘要,owner_user_id使用拼图作者用户 ID。- 下一关切换到新
profile_id时按同一规则再次写入。 - 排行榜提交携带的
elapsedMs是本关可观测时长,后端按增量累计到profile_dashboard_state.total_play_time_ms。
建议字段:
entry_id唯一主键。profile_id当前关卡作品profile_id。grid_size当前成绩对应的拼图网格规格,至少区分3x3与4x4。user_id成绩所属真实用户 ID。nickname成绩展示昵称。当前优先使用提交时的用户显示名快照。best_elapsed_ms用户在该关卡该规格下的最佳通关耗时。last_run_id最近一次刷新该最佳成绩的运行态run_id。updated_at最后一次刷新时间。
5. 排行榜口径
排行榜必须遵守下面规则:
- 只读真实成绩表。
- 同一用户在同一
profile_id + grid_size下只保留 1 条最佳成绩。 - 排序按
best_elapsed_ms从小到大。 - 同耗时按
updated_at更早者优先,再按user_id稳定排序。 - 返回前
N条,当前阶段固定10条即可。 - 当前用户如果在榜单内,需要标记
isCurrentPlayer = true。
6. 接口落地
新增拼图排行榜提交接口:
POST /api/runtime/puzzle/runs/:runId/leaderboard
请求体至少包含:
profileIdgridSizeelapsedMsnickname
返回体采用现有 PuzzleRunResponse,但要求:
run.currentLevel.leaderboardEntries返回真实榜单。run.leaderboardEntries同步返回当前关卡真实榜单,方便现有结算弹窗兼容读取。
7. 前端改动规则
- 删除
puzzleLocalRuntime.ts中本地演示榜单构造逻辑。 - 本地通关后,运行态只保留真实通关耗时,不再生成假昵称榜单。
- 结算弹窗显示时,如果真实榜单尚未回写完成,可以显示加载态;但不能回退到假数据。
- 下一关开始后,当前关卡榜单状态清空。
7.1 2026-04-29 与前端拖动裁决的对齐
当前拼图拖动、合并、拆分与通关判定完全由前端运行态负责,后端排行榜接口只负责真实成绩表与榜单聚合:
- 排行榜提交不得依赖 SpacetimeDB 里的旧棋盘快照已经通过后端拖动接口进入
cleared。 - 后端仍校验
profileId、gridSize、昵称和成绩,并把当前提交写入真实成绩表。 - 后端响应里的
leaderboardEntries是唯一需要合并回前端当前 run 的数据。 - 前端不能用排行榜响应里的旧棋盘快照覆盖本地拖动后的棋盘,否则会把刚刚通关的前端状态回滚。
8. 测试要求
至少覆盖:
- 通关后不会再生成本地假榜单。
- 同一用户重复通关同一关卡时,只保留更优成绩。
- 不同用户成绩会按耗时正确排序。
3x3与4x4不混榜。- 下一关开启后上一关榜单不会污染新关卡。