












前段时间,我给博客塞了一套游戏系统。原因也不复杂。普通博客的玩法基本都是打开文章、看完、退出,流程稳定得像新手教程。我想让它多一点可以探索的东西,于是加了等级、经验、成就和特殊事件,后面还打算继续往上叠功能。
至于这些东西要靠什么串起来?当然是存档。整套游戏系统的脑洞在这里:想把博客做得像一场游戏。
最开始设计存档时,我优先考虑的是防篡改。毕竟等级、经验和成就以后都会影响其他功能。如果浏览器改几个数字就能直接满级,那这套系统也不用玩了,大家打开控制台输入一串代码就能速通。所以第一版的原则非常直接:不信任本地数据,一切以服务端存档为准。
经验和成就在服务端结算,浏览器只负责显示。LocalStorage 最多在断线时临时顶一下,重新连接后还是由服务端存档覆盖。匿名访客则通过 Cookie 识别身份,提交评论后再尝试把匿名档合并到评论身份。安全性看起来没问题。甚至有点过于自信。

然后 Bug 就开始刷新了。
第一版只回答了一个问题:
这份数据可信吗?
却漏掉了另一个更重要的问题:
这份存档到底是谁的?
当时的身份主要依赖匿名 Cookie 和评论 Cookie,登录账号并没有真正参与存档归属。结果就是:同一个账号换台设备,找不回原来的进度;同一台设备换个账号,还是可能继续用原来的存档;服务端一旦识别到另一份记录,还会理直气壮地覆盖本地状态。
防作弊确实成功了。顺便也把正常玩家防出去了。
这就像为了避免别人修改存档,直接把读档按钮一起删掉。安全评分很高,游戏体验直接 GG。
最初我一直在纠结:本地存档和服务端存档冲突时,到底该相信哪一边?后来发现,这个问题从一开始就问歪了。本地数据当然不能直接当成可信存档,但正常访客产生的进度也不能说扔就扔。真正需要拆开的其实是三件事:
把这三件事混在一起,逻辑迟早会打结。拆开之后就简单多了:服务端继续负责校验数据,匿名存档负责保存登录前的正常进度,账号主存档负责长期归属,设备绑定则负责决定当前该读取哪一份档。匿名档可以并入账号主档,但两个账号的主存档不能自动混合。设备可以换绑,旧会话却不能靠刷新把绑定抢回去。边界锁好,剩下的交给流程。

第二版没有取消服务端校验,也没有开始无条件相信浏览器。真正改变的是:系统不再把“本地不可信”理解成“本地进度可以随便丢”。
访客没有登录时,设备拥有自己的匿名档;登录后,经过服务端确认的匿名进度可以进入账号主档。账号换到其他设备时,绑定会跟着迁移;同一台设备切换账号时,系统先断开旧关系,再建立新关系,绝不会把两份账号主档熔成一锅。
退出登录也不会顺手删档。退出账号只是结束登录状态,不是按下“删除存档”。博客又不是什么高难度 Roguelike(死亡后删档重来),没必要每次登出都让人从 LV.1 重开。
这套逻辑更像“滚动绑定”。同一时间只认一组有效的账号与设备关系,设备迁移时把归属交接清楚。少一点看似智能的自动操作,反而更不容易串档。
说到底,第一版不是代码少写了一个判断,而是设计目标少算了一项。我当时把“真实性”当成了存档系统的全部,却忽略了另外两条同样重要的属性:
只保证真实性,最多能得到一份没人改得动的存档。至于玩家还能不能找到它,那就全看运气了。现在的方案肯定也不是最终版本。以后等级、成就和特殊事件继续增加,新的边界情况大概还会从地图角落里冒出来。没关系,发现 Bug 就打补丁,遇到 Boss 就拆机制。反正做这种系统,本来就是边玩边更新。
至少这一次,存档还在,玩家不用删号重练。
算通关。暂时的。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。