ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

World of ClaudeCraft 服务端揭秘:20Hz 权威同步、兴趣范围快照与 Postgres 持久化设计

World of ClaudeCraft 服务端揭秘:20Hz 权威同步、兴趣范围快照与 Postgres 持久化设计 World of ClaudeCraft 服务端揭秘20Hz 权威同步、兴趣范围快照与 Postgres 持久化设计【免费下载链接】world-of-claudecraft项目地址: https://gitcode.com/gh_mirrors/wo/world-of-claudecraftWorld of ClaudeCraft 是一款经典风格的微 MMO其核心是一台服务端权威的游戏服务器客户端只以 20Hz 上报移动意图和指令所有战斗、掉落、任务和金币结算都在服务端唯一的一份确定性模拟中完成。本文带你揭秘它的三大支柱——20Hz 权威同步循环、兴趣范围快照裁剪、Postgres 持久化设计看看一个多人在线世界如何做到又快、又稳、又公平。一个模拟核心三端同源World of ClaudeCraft 最特别的地方是整个游戏逻辑只有一份代码src/sim/目录下的确定性模拟核心同时跑在三个宿主上——离线浏览器世界、在线权威服务器、无头强化学习环境headless/python/。这带来两个直接好处公平服务端跑的就是和客户端离线世界完全相同的规则不存在客户端算一套、服务器再算一套的双标可验证模拟固定 20Hz 步进DT 1/20所有随机数都走统一的Rng种子序列同一种子复现同一个世界。架构说明详见根目录 CLAUDE.md 的 Architecture 一节。20Hz 权威同步主循环是怎么转的整个在线世界的心跳在 server/game.ts 的start()方法里。它并不简单地每 50ms 调一次 tick而是用经典的固定步长 累加器模式setInterval每 50ms 触发一次用process.hrtime.bigint()量出真实流逝时间dtdt累入acc然后while (acc DT)循环执行整数个 50ms 逻辑步——CPU 快就补跑CPU 慢也不会加速世界每一步依次执行清理过期输入 → 消费移动帧 →sim.tick()推进世界 → 路由战斗/事件 → 反作弊观察一次触发内所有步跑完后才统一广播快照并把迟到了多少记入lateness相位供性能剖析使用。setInterval 触发 (≈50ms) ├─ 量取真实 dt累入 acc ├─ while (acc DT) │ ├─ 消费玩家移动意图20Hz 上报 │ ├─ sim.tick()权威世界推进一步 │ └─ 事件路由 / 反作弊 ├─ broadcastSnapshots()兴趣范围裁剪后下发 └─ flushPeriodicSaves()到期则触发自动存档几个面向新手的好理解点循环体是带护栏的整个 tick 包在runGuarded里任何一步抛错只跳过本轮并打日志下一轮自动恢复——单个故障永远饿不死整个服务器客户端 20Hz 上报服务端 20Hz 消化输入按seq序列号折叠server/input_seq.ts丢帧、乱序都有确定性的补偿规则服务器从不信任客户端伤害、掉落、金币、经验全部在Sim内结算客户端只是一个渲染器怎么改包都改变不了结果。兴趣范围快照只发你看得见的世界千人同服时最贵的成本是把每个人身边发生的事都广播出去。World of ClaudeCraft 的答案是兴趣范围管理Interest Management策略集中在 server/interest_policy.ts 一组纯函数里用双半径滞回控制每个玩家能看到哪些实体。规则很直白实体类型进入兴趣半径脱离兴趣半径玩家 / 怪物120 码130 码NPC120 码130 码进入半径 脱离半径刚进入视野的实体用较近的 120 码判断而已知的实体允许到 130 码才移除——这 10 码的滞回带避免了玩家在边界来回走动时实体疯狂出现-消失-出现的抖动每格只扫一次广播路径先把世界按网格分格每个有人占用的格子只收集一次候选集再按每个视角的精确半径做二次筛选避免每格 × 每视角的重复遍历竞技场特例同一竞技场槽位内队友和场地设施放宽到 300/320 码保证小地图和队伍框全场地可读而敌方玩家仍按普通半径裁剪——隐藏敌人是服务端的工作不是客户端的。快照帧本身分self/ents/keep三段自己角色的状态、兴趣范围内的实体列表、以及要继续追踪的已知实体 ID。配合 delta 键机制字段只在变化时下发带宽随人数增长被压得相当平。Postgres 持久化角色是 JSONB写的是带围栏的队列持久化设计记录在 server/CLAUDE.md 的 Persistence model 一节核心思想可以概括为三句话1. 角色整体存成一个 JSONB 大字段。等级、装备、背包、银行、任务、金币、天赋……全部序列化进characters.state。同一 blob 的原子性是防刷道具的基石银行永远不会有自己的独立行也就不存在角色回滚了、银行没回滚的撕裂窗口。2. 每个角色一把加载租约character_leases。玩家握手时拿到 90 秒 TTL 的租约自动存档循环里持续心跳释放时带 nonce 围栏。两个进程永远不可能同时加载同一个角色而每一次存档写入都携带租约 nonce只有行上仍是这个 nonce 才会落库——被顶掉的僵尸会话再也覆盖不了线上状态。3. 所有持久写入走每角色 FIFO 队列。自动存档、离场刷盘、市场托管入库全部进入GameServer.enqueueCharacterWrite排成的顺序队列提交顺序就是入队顺序杜绝旧存档覆盖新存档。存档节奏也很克制每 30 秒自动存档主循环里的flushPeriodicSaves加上离场和SIGINT/SIGTERM关停时的saveAll断线不等于下线掉线的会话由 server/linkdead.ts 保留在世界里 5 分钟LINKDEAD_GRACE_MS玩家重连直接续上角色不丢一进程一服务器realm所有角色/公会/好友按REALM隔离共享一个DATABASE_URL建表 DDL 用pg_advisory_xact_lock串行化多进程并发启动也不会打架。数据库底座在 server/db.tspg连接池、核心SCHEMADDL 与ensureSchema还有一套超时阶梯连接 语句默认 重查询专用宽限 驱动级兜底防止一条慢查询拖垮整个池。性能护栏让广播每趟只建一次多人 MMO 的服务端最怕看起来便宜、随时间变贵的隐性成本。World of ClaudeCraft 在 server/CLAUDE.md Hot paths 一节把这些经验写成了硬性规范全域共享的读数每趟广播只构建并序列化一次server/realm_readout_memo.ts事件帧每批只 stringify 一次后经sendRaw发出绝不逐会话重复会随服务器年龄增长的集合市场挂牌簿、邮箱、订单板禁止直接进每 tick 的自状态路径必须挂修订计数器 节奏门数据没变就不重建成本必须与变化量成比例而不是与整本账成比例30 秒自动存档重写一封 89MB 的邮件簿会卡 250ms这类事故被剖析器saves/lateness相位钉住复盘记录见 docs/api-pipeline/每张无限增长的表必须在同一次改动里注册保留期清理server/retention_sweep.ts 夜间批量清扫。这些规则背后是真实的线上事故驱动——新鲜世界的压测永远看不到老世界才会长出来的集合的代价所以项目要求任何新快照读取都必须在种过上千行的集合上实测并留档。小结三个设计换三个承诺设计换来的承诺20Hz 固定步长权威循环同一种子同一世界结果公平可复现兴趣范围双半径快照千人同服带宽和 CPU 依然平稳JSONB 租约 FIFO 存档断线 5 分钟可续写入永不撕裂如果你想动手读代码建议的路线是CLAUDE.md 的架构总览 → server/game.ts 的start()主循环 → server/interest_policy.ts 的兴趣策略 → server/CLAUDE.md 的持久化与热路径章节再配 tests/ 里tests/bandwidth.test.ts、tests/snapshots.test.ts这类钉死行为的测试基本就能把 World of ClaudeCraft 服务端的骨架摸清楚。【免费下载链接】world-of-claudecraft项目地址: https://gitcode.com/gh_mirrors/wo/world-of-claudecraft创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表