每日与每周任务——一个让你回来的理由
现在每一局结束都会推进一组每日与每周任务,在你完成任意一项的那一刻发放 XP,并为全新的每周排行榜提供积分。

通俗版
在此之前,opolyx 里唯一的养成只是赢下一局后的一次性奖励,日复一日没有什么可追逐的。任务改变了这一点:一小组每日与每周目标,会在你每次结束对局时向前推进,无论输赢。
你无需领取,也没有按钮要按——对局结束的那一刻,服务器就会检查你的任务,为你完成的那些结算,并把 XP 直接加到你的等级上。同时会有六个任务在进行:
- 每日——玩 1 局、玩 3 局、赢 1 局。
- 每周——玩 10 局、赢 3 局、在极速模式赢 3 局。
- 每日任务每天重置;每周任务每周一重置。
| 任务 | 频率 | 目标 | 奖励 |
|---|---|---|---|
| 玩一局 | 每日 | 1 | +50 XP |
| 继续玩 | 每日 | 3 | +120 XP |
| 赢一局 | 每日 | 1 | +150 XP |
| 常规 | 每周 | 10 局 | +300 XP |
| 连胜中 | 每周 | 3 胜 | +400 XP |
| 极速恶魔 | 每周 | 3 场极速胜利 | +400 XP |
结束对局还会赢得每周排行榜积分,所以你玩得越多,爬得越高。排行榜每周重置,让每个人在周一早晨都有一次冲顶的干净机会。
技术细节
一整套留存循环的表结构其实早已存在,只是一直闲置、无人读取——missions / user_missions(频率、目标、进度、xp_reward)以及 weekly_top(week_start、积分)。迁移 0031 把它接入了已有的结束奖励路径,而不是另起炉灶。
在真正结束一局时,daemon 会遍历每一名真人玩家,并调用一个 service-role 的 RPC。它推进本周期内该结束所满足的每个任务,在首次越过目标时发放 XP,并累加到每周积分之中:
-- grant_play_rewards(p_game, p_user, p_won): security definer, service-role only
-- daily cadence = current_date; weekly = date_trunc('week', now())
-- weekly_top.points += 20 (play) + (won ? 200 : 0) + mission_xp_earned
-- idempotent per (game_id, user_id) via the game_play_grants guard; bots skipped| 事件匹配 | 推进 | 积分 |
|---|---|---|
| {"event":"play"} | 每次结束 | +20 |
| {"event":"win"} | 仅胜利 | +200 |
| {"event":"play","mode":"speed"} | 仅极速对局 | +20 |
幂等性靠一行按(对局,用户)的守卫记录来保证,因此重试的提交绝不会重复发放。应用迁移时暴露了一个提权陷阱:Postgres 的默认权限会把新函数的 EXECUTE 授予 anon/authenticated,而 revoke … from public 并不会移除它。一个任何已登录用户都能调用的 SECURITY DEFINER 奖励函数就是一座 XP 农场——通过 revoke … from public, anon, authenticated 修复,使得只有 {postgres, service_role} 能调用它,与 award_game_winner 保持一致。
目前奖励只有 XP——金币属于变现路线,而那需要先有一个消耗出口。游玩页面的面板和排行榜都在客户端读取当前周期的进度,并把“周”锚定到 Postgres 所用的同一个周一边界,因此两者永远不会不一致。
