serverless-web-architecture-supplement
综合前述的所有系统设计、数值矩阵、Buff 状态机、双币经济模型、以及存读档交互方案,整套设计已经具备了极高的完备度。但要让这份方案在 **Web 端无服务器架构、且支持 WebRTC 联机(如图一所示的“江湖帮工客堂”)**的开发环境中真正达到“开箱即用”的生产级标准,建议补充以下针对 Web 平台技术特性及联机机制的“最后一公里”补充方案:
《同福客栈》无服务器 Web 端经营体系补充方案(联机与存储专题)
补充一、 WebRTC 联机(帮工结盟)下的双币与成就结算机制
根据图一(横版)右侧的 “P2P 联机结盟(我是大掌柜 / 我是帮工)” 界面,游戏支持通过 WebRTC 进行点对点联机。在“无中心服务器”和“双币隔离”的框架下,联机时的存盘、结算与成就判定规则如下:
1.1 数据归属与同步原则(主客分离)
- 大掌柜(Host - 房主):
- 提供当前的经营存档(PlaythroughSaveSlot),作为联机的**“物理真值”**。
- 所有客栈经营数据(银两、大堂设施、食材、Buff)均以大掌柜的本地浏览器数据为准,并实时通过 WebRTC DataChannel 广播给帮工。
- 帮工(Client - 客人):
- 不加载自己的单局经营存档,仅以“雇员”身份接入大掌柜的客栈。
- 帮工操作老白“点穴”或进行“对账”时,向大掌柜发送 RPC 操作指令,由大掌柜的浏览器进行计算后再同步回执。
1.2 联机状态下的“双币”结算
在无服务器环境下,为防止帮工玩家通过联机“白嫖”或恶意刷币,联机收支结算采用如下分流规则:
联机营业中发生交易(如客官结账 10 两)
│
▼
┌──────────────────────────────────────────┐
│ 大掌柜(Host)浏览器结算 │
└────────────────────┬─────────────────────┘
├─────────────────────────────────────────────────┐
▼ ▼
【大掌柜单局银两 +10 两】 【帮工实时佣金结算】
- 写入大掌柜本地 SaveSlot - 帮工属于临时雇员
- 用于维持客栈日常运转 - 无法带走大掌柜的银两
│
▼
【转换至帮工全局账号】
- 按比例转换:10 两 = 1 点 阅历
- 实时/下线时直接注入帮工的
GlobalProfile.legacyPoints
1.3 联机下的全局成就判定
当大掌柜与帮工联机时,产生的游戏事件会对双方的成就系统产生双向反馈:
- 大掌柜成就更新:只要客栈内发生了事件(无论是由大掌柜还是帮工操作),大掌柜的本地事件总线(EventBus)均会触发并记录(如 EVENT_THIEF_CAUGHT 计数)。
- 帮工成就更新:帮工在协助经营时,自己亲自执行成功的操作(如成功点住一次小偷),大掌柜的浏览器会发送一个 P2P_EVENT_TRIGGER 封包给帮工。帮工的浏览器收到后,会触发其本地全局成就的计数,从而在不破坏单局存档的前提下,帮助帮工解锁其个人的全局成就。
补充二、 前端本地存储优化与防爆(Local Storage Pruning)
浏览器的 LocalStorage 存储容量通常限制在 5MB 左右。如果多周目的历史记录、日志(如图二底部的“江湖消息”)以及 Buff 实例不断累积,可能会引发 QuotaExceededError 导致游戏崩溃。
2.1 运行时“江湖消息(Log)”剪枝算法
图二底部的“江湖消息”是文字挂机游戏的信息源泉,但在存档时无需全量保存。
- 内存暂存:所有历史消息均在内存(RAM)中的一个 Array 队列中维护。
- 存档剪枝:当执行“自动/手动记账”时,系统仅保留最新 50 条消息写入 LocalStorage。其余消息在序列化前被丢弃。
- JSON 压缩:在序列化后,推荐使用轻量级的前端压缩库(如 lz-string)对 Base64 数据进行二次压缩,将体积缩减至原本的 15%
- 30%。
2.2 跨版本存档迁移器(Data Migration Engine)
作为持续更新的 Web 游戏(当前版本 v1.15.1),未来升级版本时,旧的本地存档极易因为字段缺失而引发 JavaScript Null 指针崩溃。
- 设计一个 ProfileMigrator 类,在游戏启动加载 loadProfile 时进行版本嗅探:
export class ProfileMigrator { private static readonly CURRENT_VERSION = '1.16.0';
public static migrate(rawData: any): any { const version = rawData.version || '1.15.1';
if (version === this.CURRENT_VERSION) return rawData;
let migratedData = { ...rawData };
// 递进式升级
if (version === '1.15.1') {
// 1.15.1 -> 1.16.0 升级:引入了新的全局特权字段,进行空值补正
migratedData.purchasedLegacies = migratedData.purchasedLegacies || [];
migratedData.version = '1.16.0';
}
return migratedData;
} }
补充三、 响应式视口断点与布局转换 (Responsive Breakpoints)
如图一(横版)和图二(竖版)所示,游戏需要在不同设备上提供完全不同的交互布局。利用 CSS Media Queries 和运行时状态机,需要设定严格的切换边界:
3.1 视口断点设计
┌────────────────────────────┬─────────────────────────────┬───────────────────────────┐ │ 竖版布局 (Portrait) │ 过渡状态 (Adaptive) │ 横版布局 (Landscape) │ ├────────────────────────────┼─────────────────────────────┼───────────────────────────┤ │ 宽度 < 768px (手机端) │ 宽度 768px - 1024px (平板) │ 宽度 > 1024px (PC/Mac) │ │ │ │ │ │ - 单栏滚动布局 │ - 核心画布居中 │ - 双栏栅格化布局 │ │ - 底部固定 Tab 导航 │ - 左右留白或侧边栏收起 │ - 左右分区展示 │ │ - 简化大堂地图,卡片展示 │ │ - 全量大堂网格图展示 │ └────────────────────────────┴─────────────────────────────┴───────────────────────────┘
- UX 体验一致性处理:
- 在宽度临界点发生切换时,游戏核心状态机(currentDay、silver)绝不刷新,仅重构 DOM 树。
- 正在发生的主动动作(如老白的“点穴”)在横屏与竖屏下的 CD(冷却时间)和状态保持无缝同步。
补充四、 核心运行时生命周期(Game Loop)序列化
在挂机游戏中,游戏的主循环(Tick)决定了数值衰减、Buff 结算和状态判定的顺序。建议在数值配置文件中严格规范一秒一次的 “一分钟游戏循环(1 Game Minute = 1 Real Second)” 流程顺序:
┌────────────────────────────────────────────────────────┐ │ 每秒一次的运行时主循环 (Loop) │ ├────────────────────────────────────────────────────────┤ │ 1. 【时间递增】: 游戏时间增加 1 分钟 │ │ │ │ 2. 【数值自然衰减】: 扣减清洁度、安防值、员工心情(按Buff修饰)│ │ │ │ 3. 【运行时 Buff 状态Tick】: 遍历计算 Buff 持续时间 -1 分钟│ │ - 若持续时间归零,自动执行卸载回调并更新标签池 │ │ │ │ 4. 【状态机状态评估】: 检查当前全局标签池 (Tags) │ │ - 根据优先级匹配当前客栈经营状态是否需要强制切换 │ │ │ │ 5. 【自动运维执行】: 检查自动维护启动线 │ │ - 若触发,扣减银两/耗材,执行打扫/值守,拉升数值 │ │ │ │ 6. 【UI 与日志刷新】: 向大堂渲染数据,派发“江湖消息” │ └────────────────────────────────────────────────────────┘
💡 结语
补充上述四项设计(联机 P2P 数据路由、Web 存储剪枝与迁移、自适应断点、游戏主循环流向)后,这份《同福客栈》核心数值与经营状态系统设计文档已涵盖了从**“市井江湖世界观”到“前端技术落地细节”**的完整链路。开发团队可以直接根据上述 TypeScript 接口定义、JSON 格式规范与生命周期伪代码进行底层代码编写和系统构建。