Deep-Dive Technical Dissection

深入拆解 World of ClaudeCraft

World of ClaudeCraft —— 由 Claude Fable 5 自主实现的完整魔兽世界游戏,一个纯 TypeScript 写成的微 MMO,以同一套确定性仿真核心同时驱动在线多人、离线单机和 Gym 风格强化学习训练三种截然不同的运行上下文。本文从架构、渲染管线、网络协议、AI 集成到过程化生成,层层拆解其设计哲学与实现细节。

World of ClaudeCraft — Party Questing gameplay screenshot
World of ClaudeCraft 实机游戏界面 — 多人组队战斗场景
884GitHub Stars
TypeScript 5.5核心语言
v0.7.0当前版本
MIT开源许可

一、项目概述

World of ClaudeCraft(WoCC)是一个开源的经典 MMO 风味微 MMO,全部使用 TypeScript 编写。它在浏览器中呈现实时 3D 多人游戏——包含 9 个职业、130+ 技能、怪物 AI、地下城、团本、竞技场、交易系统,以及完整的经典风格 UI——全部由单一权威 Node.js 服务器和 PostgreSQL 数据库支撑。

它最厉害的设计在于:同一套确定性仿真核心同时驱动三种截然不同的运行上下文——在线多人(WebSocket 连接共享服务器)、离线模式(整个世界在浏览器内运行,无需服务器)、无头 RL 训练(仿真暴露为 Gym 风格环境,供 Python 训练强化学习代理)。

二、完整项目结构

world-of-claudecraft/
├── .env.example                     # 60+ 环境变量模板
├── docker-compose.yml               # 4 服务栈: postgres + game + mediawiki-db + mediawiki
├── Dockerfile
├── vite.config.ts                   # Vite 8 配置
├── tsconfig.json
├── package.json                     # v0.7.0, ESM 模块
├── README.md                        # 12 种语言多语言支持
│
├── src/
│   ├── main.ts                      # 客户端入口, 世界种子, 场景设置 (~110KB)
│   ├── world_api.ts                 # IWorld 接口, Sim 和 ClientWorld 共享
│   │
│   ├── sim/                         # ★ 确定性游戏核心 (无 DOM/Three 导入)
│   │   ├── sim.ts                   # ~5,000+ 行 — tick 循环, 战斗, AI, 一切
│   │   ├── types.ts                 # 35KB 共享类型 + 所有调优常量 + 原版公式
│   │   ├── entity.ts                # Entity 工厂 + recalcPlayerStats (单一真相源)
│   │   ├── rng.ts                   # Mulberry32 PRNG + FBM 噪声 (地形)
│   │   ├── world.ts                 # 地形高度 + 装饰生成
│   │   ├── colliders.ts             # 静态碰撞 + 滑动解析
│   │   ├── dungeon_layout.ts        # 整数地下城布局
│   │   ├── pathfind.ts              # 局部 A* 寻路
│   │   ├── threat.ts                # 原版仇恨表数学
│   │   ├── spatial.ts               # SpatialGrid 半径查询
│   │   ├── obs.ts                   # RL 观察表面
│   │   └── content/                 # 13 个文件 — 所有游戏内容数据
│   │       ├── classes.ts           # 73KB — 9 职业, 130+ 技能, 天赋树
│   │       ├── zone1.ts             # 32KB — Eastbrook 区域
│   │       ├── zone2.ts             # 44KB — Glimmermere 区域
│   │       ├── zone3.ts             # 52KB — 额外区域
│   │       ├── dungeons.ts          # 16KB — 地下城怪物/Boss/掉落
│   │       └── temple.ts            # Drowned Temple 团本
│   │
│   ├── render/                      # ★ Three.js 3D 渲染管线
│   │   ├── models.ts                # 12 个生物族 + 动画
│   │   ├── props.ts                 # 过程化建筑生成
│   │   ├── textures.ts             # 41KB — 过程化纹理 (零资源文件!)
│   │   ├── terrain.ts              # 高度图 → 几何体
│   │   ├── water.ts                # 动画水面 (自定义着色器)
│   │   └── vfx.ts                  # 18KB — 技能特效, 粒子, 阴影
│   │
│   ├── game/                        # 输入, 相机, 音频
│   │   ├── audio.ts                 # WebAudio 过程化音效 (零音频文件!)
│   │   ├── music.ts                 # 动态音乐系统
│   │   ├── input.ts                 # 键盘/鼠标输入
│   │   └── camera.ts               # 第三人称相机
│   │
│   ├── ui/                          # HTML/CSS UI 层
│   │   ├── actionbar.ts            # 动作条
│   │   ├── unitframes.ts           # 单位框架
│   │   ├── chat.ts                 # 聊天窗口
│   │   └── ...                     # 15+ UI 组件
│   │
│   └── net/                         # 网络层
│       ├── connection.ts           # WebSocket 客户端
│       └── protocol.ts             # 消息类型定义
│
├── server/                          # ★ 权威游戏服务器
│   ├── main.ts                     # 入口, WebSocket 处理, 玩家管理
│   └── db.ts                       # PostgreSQL 持久化
│
├── headless/                        # ★ 无头 RL 训练环境
│   └── env.ts                      # Gym 风格环境包装器
│
└── python/                          # Python RL 训练脚本
    └── train.py                     # 训练循环 + 算法
关键架构约束:src/sim/ 目录下的所有代码不得导入 DOM、Three.js 或任何浏览器 API。这是确定性保证的核心——同一份 Sim 代码在浏览器、服务器和无头环境中的行为完全一致。

三、确定性仿真核心:架构基石

3.1 为什么确定性是第一约束

在传统 MMO 中,客户端只负责渲染,所有游戏逻辑运行在服务器上。WoCC 走了一条更激进的路:同一套仿真代码运行在三个完全不同的上下文中——浏览器(客户端预测 + 离线模式)、Node.js 服务器(权威游戏状态)、无头环境(RL 训练)。

这要求仿真必须是比特级确定性的:给定相同的初始种子和相同的输入序列,输出必须完全一致,无论运行环境如何。

3.2 确定性保证机制

1. 固定种子 PRNG

使用 Mulberry32 算法——一个 32 位种子确定性伪随机数生成器。所有随机性(暴击、掉落、地形生成、仇恨波动)都通过这个单一 RNG 流。服务器和客户端用相同种子初始化,保证随机序列完全一致。

2. 固定步长 Tick

游戏循环以固定时间步长运行(通常 100ms/tick),与帧率完全解耦。不使用 requestAnimationFrameDate.now() 推进逻辑。每次 tick 接收确定性输入,产出确定性输出。

3. 有序实体迭代

所有实体在每个 tick 中按固定 ID 顺序迭代处理。JavaScript 的 MapSet 迭代顺序在 ES6+ 中已规范化,但 WoCC 仍显式排序以确保跨环境一致性。

4. 模块依赖隔离

sim/ 目录严格禁止导入 render/ui/net/ 或任何浏览器 API。ESLint no-restricted-imports 规则在 CI 中强制执行这一约束。

3.3 Tick 循环内部

每次 tick() 调用按以下顺序处理:

// sim.ts — tick() 的简化结构 tick(actions: SimAction[]): SimEvent[] { const events: SimEvent[] = []; // 1. 处理玩家输入 (移动, 施法, 交互) for (const action of actions) { this.applyAction(action, events); } // 2. 更新冷却和光环 (GCD, 冷却时间, Buff/Debuff) this.updateCooldownsAndAuras(dt, events); // 3. 怪物 AI (仇恨评估, 寻路, 技能选择) this.updateMobAI(dt, events); // 4. 移动解析 (碰撞检测, 滑动) this.resolveMovement(dt, events); // 5. 投射物更新 this.updateProjectiles(dt, events); // 6. 生命周期 (生成, 死亡清理, 尸体消失) this.updateLifecycle(dt, events); // 7. 资源再生 (HP/MP 每秒再生) this.updateRegeneration(dt, events); return events; // 所有状态变化作为事件流发出 }

每一步都是纯函数式变换:接收当前状态和输入,产出新状态和事件。这种设计使得仿真可以在任何地方重放、快照和分支。

四、Three.js 与 WebGL 渲染管线深度拆解

4.1 整体渲染架构

WoCC 使用 Three.js r165 作为 3D 渲染引擎,配合 n8ao(GPU SSAO 环境光遮蔽)和 postprocessing 6.36.0(Bloom 泛光 + 色调映射)构建完整的后处理管线。渲染代码集中在 src/render/ 目录,与仿真核心完全解耦——渲染只消费 Sim 产生的状态快照,不参与任何游戏逻辑。

渲染管线概览:

// 每帧渲染管线 (简化) // 1. Sim 产生世界状态快照 const snapshot = world.getSnapshot(); // 2. 地形渲染: Heightmap → BufferGeometry renderTerrain(snapshot.terrain); // 3. 水面渲染: 自定义 ShaderMaterial + 顶点位移 renderWater(snapshot.waterLevel); // 4. 实体渲染: SkeletalMesh + 动画混合 for (const entity of snapshot.entities) { renderEntity(entity); } // 5. 后处理: SSAO → Bloom → ToneMapping composer.render();

4.2 Three.js r165 技术细节

Three.js 是对 WebGL API 的高层抽象。它不直接暴露 WebGL 的 gl.drawArrays(),而是提供 Scene Graph(场景图)、Material(材质)、Geometry(几何体)等高层概念。r165 版本引入了多项关键优化:

  • WebGPU 后端支持:除 WebGL 2.0 外,r165 实验性支持 WebGPU,在支持的浏览器上提供更低的 draw call 开销
  • GPUParticleSystem:粒子计算完全在 GPU 上完成,WoCC 的 vfx.ts 大量使用此特性来渲染法术效果
  • InstancedMesh:草、树木、石头等重复对象使用实例化渲染,将数千个对象的 draw call 合并为一次 GPU 调用
  • SkeletonHelper + AnimationMixer:骨骼动画系统——models.ts 中 12 个生物族的行走、攻击、死亡动画通过关键帧插值实现

4.3 n8ao — GPU 加速的环境光遮蔽

n8ao(N8AO, v1.10.1)是一种屏幕空间环境光遮蔽(SSAO)实现,与传统的 SAO/HBAO 不同,它完全在 GPU 上通过计算着色器执行:

  • 深度重建法线:从深度缓冲重建世界空间法线,避免 G-Buffer 的额外显存开销
  • 自适应采样:根据深度不连续性动态调整采样半径和采样数,减少噪点
  • 时间抗锯齿(TAA):利用上一帧的 AO 结果进行时域滤波,消除闪烁
  • 低延迟设计:总耗时 <1ms @ 1080p,适合实时 MMO 场景

4.4 postprocessing 库 — Bloom 与色调映射

postprocessing 6.36.0 是一个基于 EffectComposer 模式的后处理框架。WoCC 使用以下 effect pass:

Effect用途关键参数
BloomEffect法术光晕、UI 高亮、阳光散射threshold=0.8, intensity=1.2, mipmapBlur
ToneMappingEffectHDR → LDR 转换ACES Filmic 模式
VignetteEffect屏幕边缘暗角darkness=0.3, offset=0.5
SMAAEffect子像素形态学抗锯齿比 FXAA 更锐利

4.5 Canvas 2D 在 UI 中的角色

虽然 3D 世界使用 WebGL,但 WoCC 的 UI 层大量使用 Canvas 2D API 进行过程化绘制。具体场景:

  • 过程化图标:法术图标、物品图标、Buff/Debuff 图标全部在 <canvas> 上通过 2D API 实时绘制(形状、渐变、阴影),而非加载 PNG 文件
  • 迷你地图:世界地形的俯视图通过 Canvas 2D 绘制,实时反映玩家位置和可见实体
  • 血条和状态条:单位头顶的生命条、施法条使用 Canvas 2D 绘制以实现像素级精确控制

五、过程化生成全栈技术深挖

WoCC 的激进理念是:一切能由代码生成的,绝不用资源文件。纹理、图标、建筑、地形、水体、动画、后处理全部过程化生成,WebAudio 零音频文件合成。下面逐一拆解每个子系统的实现原理。

5.1 过程化纹理 — textures.ts (41KB)

textures.ts 是整个项目中最大的渲染文件之一,实现了完全无外部资源文件的纹理管线。核心思路:使用 Canvas 2D API 离线渲染纹理到 OffscreenCanvas,然后转换为 Three.js CanvasTexture

// textures.ts — 过程化纹理生成的核心模式 function generateTerrainTexture(size: number, seed: number): CanvasTexture { const canvas = new OffscreenCanvas(size, size); const ctx = canvas.getContext('2d')!; const rng = mulberry32(seed); // 1. 基础色填充 (Perlin 噪声调制) for (let y = 0; y < size; y++) { for (let x = 0; x < size; x++) { const n = fbmNoise(x / size, y / size, 4, rng); ctx.fillStyle = lerpColor('#4a7c3f', '#3a5c2f', n); ctx.fillRect(x, y, 1, 1); } } // 2. 细节叠加 (小石块, 草斑, 泥土露头) addDetailLayer(ctx, rng, size, 0.15); // 3. 法线贴图生成 (从高度图推导) const normalMap = generateNormalMap(canvas); const texture = new CanvasTexture(canvas); texture.wrapS = RepeatWrapping; texture.wrapT = RepeatWrapping; texture.magFilter = LinearMipmapLinearFilter; texture.minFilter = LinearMipmapLinearFilter; texture.generateMipmaps = true; return texture; }

这种方式的优势:纹理完全平铺(tileable)、分辨率可动态调整、视觉变化完全由种子控制、无需任何磁盘资源或网络请求。

5.2 过程化地形 — terrain.ts + rng.ts

地形高度图使用 FBM(Fractal Brownian Motion,分形布朗运动)算法生成。核心在 rng.ts 中实现:

// rng.ts — FBM 地形噪声 (简化) function fbmNoise(x: number, y: number, octaves: number): number { let value = 0, amplitude = 1, frequency = 1, maxValue = 0; for (let i = 0; i < octaves; i++) { // 每层叠加不同频率和振幅的 Perlin/Simplex 噪声 value += amplitude * simplex2D(x * frequency, y * frequency); maxValue += amplitude; amplitude *= 0.5; // 振幅递减 (persistence) frequency *= 2.0; // 频率递增 (lacunarity) } return value / maxValue; // 归一化到 [0, 1] }

FBM 的原理:将多个不同尺度的噪声叠加,模拟自然界中"大尺度山脉 + 中尺度丘陵 + 小尺度岩石"的自相似分形结构。octaves 参数控制细节层数(越高越精细但计算越昂贵),persistence 控制每层振幅衰减速度。

高度图通过 PlaneGeometry 映射为 Three.js BufferGeometry——每个顶点的 Y 坐标根据高度图偏移,形成起伏的地形。不同高度区间使用不同的纹理混合(草皮→岩石→雪线),通过 MeshStandardMaterialvertexColors 或自定义着色器实现。

5.3 水体渲染 — water.ts

WoCC 的水面使用自定义 GLSL 着色器实现,完全不依赖外部纹理或资源文件:

  • 顶点着色器:使用多层正弦波叠加进行顶点位移,模拟水面波动。振幅和频率由世界种子派生
  • 片元着色器:实现菲涅尔反射(Fresnel Effect)、次表面散射近似(用于浅水区)、泡沫边缘效果(基于深度缓冲检测岸边)
  • 法线扰动:通过两层不同方向、不同速度的噪声纹理叠加来模拟水面波纹法线,全部在着色器中过程化生成
  • 反射/折射:使用 Three.js 的 WebGLCubeRenderTarget 实时渲染环境立方体贴图,着色器中采样实现反射效果

5.4 过程化建筑 — props.ts

props.ts 实现了一个过程化建筑生成器。建筑不是预制模型,而是在运行时通过参数化规则构建:

  • 建筑轮廓:随机生成矩形或多边形底面,大小随区域类型变化(城镇→大建筑,村庄→小建筑)
  • 墙体:BoxGeometry 叠加,高度随机变化,墙面使用过程化砖块纹理
  • 屋顶:ConeGeometry(尖顶)或 BoxGeometry 旋转(平顶),颜色从调色板中随机抽取
  • 门窗:墙体上的布尔裁剪或独立 PlaneGeometry 贴附
  • 变化控制:所有随机参数由种子控制,同一区域每次生成的结果完全一致

5.5 WebAudio 零音频文件合成 — audio.ts + music.ts

WoCC 最令人惊叹的技术之一:整个游戏的音频完全通过 WebAudio API 实时合成,没有任何 .mp3/.wav/.ogg 文件。这一设计决策消除了数百 MB 的音频资源,使客户端体积几乎为零,且音效可以随游戏参数动态变化。

音效合成架构

// audio.ts — 过程化音效的核心模式 function createSpellSound(type: SpellAudioType, params: AudioParams): AudioNode { const ctx = AudioContext; // 全局共享 AudioContext const now = ctx.currentTime; // 1. 振荡器层 — 基础音调 const osc = ctx.createOscillator(); osc.type = params.waveform; // 'sine' | 'square' | 'sawtooth' | 'triangle' osc.frequency.setValueAtTime(params.baseFreq, now); osc.frequency.exponentialRampToValueAtTime(params.endFreq, now + params.duration); // 2. 噪声层 — 纹理和冲击感 const noise = createNoiseBuffer(ctx, params.duration); const noiseNode = ctx.createBufferSource(); noiseNode.buffer = noise; // 3. 滤波器 — 音色塑造 const filter = ctx.createBiquadFilter(); filter.type = params.filterType; // 'lowpass' | 'bandpass' | 'highpass' filter.frequency.setValueAtTime(params.cutoff, now); // 4. 包络 — 音量随时间变化 (ADSR) const gain = ctx.createGain(); gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(params.attackVol, now + params.attackTime); gain.gain.exponentialRampToValueAtTime(0.001, now + params.duration); // 5. 效果链 const reverb = createConvolutionReverb(ctx, params.reverbMix); const delay = ctx.createDelay(params.delayTime); // 连接音频图 osc.connect(filter); noiseNode.connect(filter); filter.connect(gain); gain.connect(reverb); reverb.connect(ctx.destination); osc.start(now); osc.stop(now + params.duration); noiseNode.start(now); noiseNode.stop(now + params.duration); return gain; // 返回可控制的节点 }

各音效类型的合成策略

音效类型合成方式关键参数
脚步声短噪声脉冲 + 带通滤波器截止频率(草地低/石板高), 持续时间
法术施放振荡器扫频 + 噪声爆发起始/终止频率, 扫频曲线, 泛音列
击中/受击冲击噪声 + 低频振荡攻击时间, 衰减速度, 失真量
环境音(风/雨/火)长时间噪声 + 缓慢调制滤波器扫频, 音量 LFO, 立体声展宽
UI 交互音短正弦脉冲 + 频率跳变音高, 持续时间, 谐波数
背景音乐多层振荡器 + 序列器 (music.ts)音阶, 和弦进行, 节奏模式, 乐器包络

music.ts — 动态音乐系统

music.ts 实现了一个过程化音乐序列器,能根据游戏状态动态改变音乐:

  • 分层系统:音乐由多个独立层组成(打击乐层、和声层、旋律层),每层可独立淡入/淡出
  • 游戏状态响应:进入战斗→打击乐层音量 +30%、和声转小调;Boss 战→旋律层增加紧张音程
  • 多区域主题:每个区域有独立的音阶、节奏和乐器组合(通过不同波形模拟不同乐器音色)
  • 种子驱动变化:旋律的装饰音、节奏填充、和声转位由种子控制,保证每次进入同一区域听到相同的音乐动机

5.6 动画与后处理过程化 — vfx.ts (18KB)

vfx.ts 管理所有视觉特效。粒子系统完全在 GPU 上运行(通过 Three.js GPUParticleSystem),每个粒子的生命周期为:发射→参数更新(由 GPU 计算着色器处理)→渲染→死亡回收。

法术特效的参数化设计:每个法术定义一组视觉参数(颜色渐变、粒子形状、发射速率、生命周期、重力影响、尾迹长度),vfx.ts 在法术命中时实例化对应的粒子发射器。整个过程无需任何预制资源。

阴影方面,WoCC 使用 CSM(Cascaded Shadow Maps,级联阴影贴图)——将视锥体分割为多个深度层,近处高精度、远处低精度,在质量和性能间取得平衡。

六、WebSocket 通信协议深度拆解

6.1 整体通信架构

WoCC 使用 ws 8.21.0 库实现 WebSocket 通信。这是一个轻量级、高性能的 WebSocket 实现(客户端和服务端均使用同一库)。通信模型采用客户端→服务器单向发送操作意图 + 服务器→客户端广播权威状态的模式。

[浏览器]                          [Node.js 服务器]
  |                                    |
  |-- WebSocket 连接 ----------------->|  ws.Server(:8787)
  |                                    |
  |-- PlayerAction (JSON) ------------>|  验证 → Sim.applyAction()
  |   { type: "move", dx: 1, dy: 0 }   |
  |   { type: "cast", spellId: 42 }   |
  |   { type: "interact", target: X }  |
  |                                    |
  |<- WorldState (JSON) ---------------|  tick() → 广播状态差异
  |   { entities: [...], events: [...] }  (全量或增量, 可配置)
  |                                    |
  |<- ChatMessage (JSON) --------------|  聊天广播
  |<- SystemEvent (JSON) --------------|  系统通知

6.2 消息协议设计

客户端通过 connection.ts 管理 WebSocket 生命周期,protocol.ts 定义了强类型的消息接口。所有消息以 JSON 格式编码:

// protocol.ts — 消息类型定义 (简化) type ClientMessage = | { type: 'auth'; token: string } | { type: 'move'; dir: {dx: number; dy: number}; running: boolean } | { type: 'cast'; spellId: number; targetId?: number } | { type: 'interact'; targetId: number; action: string } | { type: 'chat'; channel: string; text: string } | { type: 'ping'; t: number }; type ServerMessage = | { type: 'world'; tick: number; entities: EntityDelta[]; events: SimEvent[] } | { type: 'chat'; from: string; channel: string; text: string } | { type: 'system'; code: string; params: Record<string, unknown> } | { type: 'pong'; t: number; serverTime: number };

6.3 关键设计决策

客户端只发意图,不发状态

客户端从不声称"我现在在坐标 (x,y)"。它只发送"我想向这个方向移动"。服务器在 Sim 中验证并执行,然后告知客户端真实结果。这从根本上消除了位置欺骗。

状态差异而非全量同步

服务器每次 tick 后广播的是状态差异(delta)而非全量世界状态。只发送自上次同步以来变化的实体属性,将典型消息体从 50KB 压缩到 2-5KB。

客户端预测 + 服务器和解

客户端在发送移动意图后立即在本地 Sim 中应用预测,不等待服务器确认。当服务器状态到达时,如果预测与实际不同,客户端平滑修正到权威位置。

心跳与断线重连

客户端每 5 秒发送 ping,服务器回复 pong。超过 15 秒未收到 pong 即触发重连。重连时服务器发送全量世界状态快照以重新同步。

七、强化学习集成:实践向深挖

7.1 整体架构

WoCC 的强化学习集成是其最独特的设计之一。headless/ 目录将游戏仿真包装成标准 Gym 风格环境,使 RL 研究者可以使用熟悉的 API(env.reset() / env.step(action) / env.render())来训练代理。

Python 训练脚本通过 Node.js 子进程与无头仿真通信,使用进程间通信(IPC)标准输入/输出管道交换观察和动作数据。

┌─────────────────────────────────────────────────┐
│  Python 训练脚本 (python/train.py)               │
│  ├─ PPO / DQN 算法                               │
│  ├─ 经验回放缓冲                                  │
│  └─ 神经网络 (PyTorch)                            │
└──────────────┬──────────────────────────────────┘
               │ stdin/stdout JSON
               ▼
┌─────────────────────────────────────────────────┐
│  Node.js 无头环境 (headless/env.ts)               │
│  ├─ Sim 实例 (与游戏服务器相同代码)                  │
│  ├─ 观察构建 (obs.ts → 观察向量)                   │
│  └─ 奖励计算                                      │
└─────────────────────────────────────────────────┘

7.2 观察空间 (Observation Space)

obs.ts 将游戏状态编码为一个固定维度的浮点向量。观察向量的结构:

// obs.ts — RL 观察向量结构 interface RLObservation { // 自身状态 (15 维) self: { hp, maxHp, mp, maxMp, // 资源 x, y, z, // 位置 level, // 等级 facing, // 朝向 isCasting, globalCooldown, // 施法状态 movementSpeed, // 移动速度 alive // 存活 }; // 目标状态 (15 维) — 最近/选中的敌方 target: { /* 对称结构 */ }; // 附近实体 (N×8 维) — 空间中最近的 N 个实体 nearby: FixedArray<8, EntityFeature>; // 冷却状态 (M 维) — 每个技能的剩余冷却时间 cooldowns: FixedArray<MAX_SPELLS, number>; // 全局上下文 (5 维) context: { inCombat, // 是否在战斗中 combatTimer, // 战斗计时器 threatPercent, // 仇恨百分比 partySize, // 队伍大小 dungeonLevel // 地下城层级 }; }

7.3 动作空间 (Action Space)

动作空间设计为离散动作空间,每个动作是一个整数 ID。动作分为几大类:

动作类别ID 范围描述
移动0–88 方向 + 停止
法术施放9–138130 个可用法术/技能
目标选择139–146切换目标 (最近/最低血/最高威胁等)
物品使用147–166药水, 食物, 绷带等
社交167–170跟随, 交易, 决斗等

7.4 奖励函数设计

奖励函数是 RL 训练的核心。WoCC 的奖励设计采用多目标加权求和

// 奖励组成 (Python 端或 env.ts 中计算) reward = ( + 10.0 * killBonus // 击杀奖励 (主要正向信号) + 2.0 * damageDealt // 造成的伤害 (每点) - 1.5 * damageTaken // 承受的伤害 (每点, 惩罚) + 0.1 * xpGained // 经验值获取 - 5.0 * deathPenalty // 死亡惩罚 + 0.5 * objectiveCompleted // 任务/目标完成 + 0.01 * explorationBonus // 探索新区域奖励 - 0.01 * idlePenalty // 空闲惩罚 (每 tick) )

7.5 训练挑战

在 WoCC 中训练 RL 代理面临几个独特挑战:

  • 稀疏奖励:击杀怪物需要一系列正确的动作序列(移动→接近→施法→维持距离→击杀),中间几乎没有正向信号
  • 大动作空间:130+ 法术的离散动作空间远大于典型 Atari 游戏,需要有效的动作空间剪枝(根据当前可用法术动态mask掉无效动作)
  • 部分可观察性:代理只能看到附近的实体和自身状态,无法观察整个游戏世界
  • 长期规划:成功的游戏需要跨多个 tick 的规划(资源管理、冷却协调),单步奖励信号弱

八、CLAUDE.md 体系:AI 原生文档的实践

8.1 什么是 CLAUDE.md

WoCC 仓库包含约 20 个 CLAUDE.md 文件,分布在几乎所有主要目录中。这不是给人类开发者看的 README,而是面向 AI 编码代理(Claude、Codex、Copilot 等)的机器可读操作手册

每个 CLAUDE.md 文件告诉 AI 代理:这个目录做什么、架构不变量是什么、修改这个目录时永远不能做的事、添加新功能的标准步骤。

8.2 CLAUDE.md 分布地图

位置主要内容
/CLAUDE.md根级项目全景:技术栈、架构原则、目录约定、构建命令
src/sim/CLAUDE.md确定性规则(禁止 DOM/Date.now()/Math.random())、tick 顺序、添加新法术的步骤
src/render/CLAUDE.md渲染管线架构、Three.js 版本约束、性能预算(draw call 上限)、纹理分辨率上限
src/game/CLAUDE.md输入处理、音频系统、相机行为
src/ui/CLAUDE.mdUI 组件规范、CSS 约定、事件冒泡规则
src/net/CLAUDE.mdWebSocket 协议、消息类型、重连策略、服务器验证规则
server/CLAUDE.md服务器启动流程、数据库模式、迁移步骤、速率限制
headless/CLAUDE.md无头环境配置、RL 集成点、观察/动作空间约定
python/CLAUDE.mdPython 训练脚本约定、依赖管理、日志格式

8.3 CLAUDE.md 的内容结构

典型的 CLAUDE.md 包含以下标准化部分:

# /src/sim/CLAUDE.md — 示例结构 ## Architecture Invariants - NEVER import from ../../render, ../../ui, ../../net - NEVER use Date.now(), Math.random(), or any non-deterministic API - ALWAYS use mulberry32() from ./rng.ts for randomness - ALL entity iteration MUST be sorted by entity.id for determinism ## File Map - sim.ts: Main tick loop, combat system, mob AI (~5000 lines) - types.ts: Shared types, tuning constants, vanilla formulas - entity.ts: Entity creation, recalcPlayerStats() - ... ## How to Add a New Spell 1. Add spell definition in content/classes.ts under the target class 2. Add spell effect handler in sim.ts 'applySpellEffect()' 3. Add visual hook in render/vfx.ts 'getSpellVFX()' 4. Register in types.ts SPELL_REGISTRY 5. Add test in tests/sim/spells/ ## Never Do Here - Do not access the network layer - Do not modify the tick order without updating ALL callers - Do not add implicit state mutations outside tick()

8.4 为什么这是 AI 时代的最佳实践

传统的代码注释和 README 是为人类设计的——期望读者有上下文、能推断未书写的内容、能容忍歧义。AI 代理恰好相反:它字面理解每个指令,不推断未明确说明的约束,会在任何未设边界的地方自由发挥。

CLAUDE.md 体系解决了这个根本问题:用 AI 代理能精确遵循的格式,编码架构规则、禁止事项和操作流程。这不是"给 AI 写文档",而是把架构约束正式化为一组可被自动执行的规则。

这一实践与 Codex 的 AGENTS.md 规范一脉相承——两者都基于同一核心理念:代码库应该能"教"AI 代理如何在其中工作

九、服务器架构

9.1 部署拓扑

WoCC 使用 Docker Compose 编排四个服务:

docker-compose.yml
┌──────────────────────────────────────────────┐
│  game-server (Node.js ESM)                    │
│  ├─ WebSocket 服务器 (:8787)                   │
│  ├─ Sim 实例 (权威游戏状态)                     │
│  └─ tick 循环 (100ms)                          │
│         │                                      │
│         ▼                                      │
│  postgres (PostgreSQL 16-alpine)              │
│  ├─ 玩家账号/角色数据                           │
│  ├─ 物品/装备持久化                             │
│  └─ 经济系统数据                                │
│                                                │
│  mediawiki (MediaWiki)                         │
│  ├─ 游戏 Wiki                                  │
│  └─ 玩家贡献内容                                │
│         │                                      │
│         ▼                                      │
│  mediawiki-db (MariaDB 11)                    │
└──────────────────────────────────────────────┘

9.2 服务器入口 — server/main.ts

服务器的核心职责:

  • WebSocket 连接管理:接受客户端连接、认证(JWT token)、会话管理
  • 玩家加入/离开:玩家上线时创建 Sim 实体、加载持久化数据;下线时保存状态
  • 输入验证每一个客户端操作在进入 Sim 之前都经过字段级验证——法术 ID 是否存在、目标是否有效、冷却是否就绪
  • Tick 回路:以固定 100ms 间隔调用 sim.tick(),将产生的 SimEvent[] 广播给相关玩家
  • 速率限制:每个客户端每秒最多 N 条消息,超出则断开连接

9.3 数据库 — server/db.ts + PostgreSQL

pg 8.21.0 客户端连接 PostgreSQL 16-alpine。数据库存储玩家账号(bcrypt 哈希密码)、角色数据(等级/装备/物品栏/技能书)、经济数据(金币/拍卖行)。设计原则:游戏运行时完全在内存中,数据库仅用于启动加载和定期持久化——模拟 tick 循环不做 I/O。

十、测试策略

10.1 测试层级

层级工具覆盖范围文件数
单元测试Vitest 4.1.8战斗公式、仇恨表、寻路、碰撞、RNG123 个 test 文件
集成测试Vitest多 tick 场景、地城流程、交易流程包含在 123 个文件中
E2E 测试Puppeteer 25.1完整用户路径(登录→移动→战斗→拾取)51 个自动化脚本
RL 环境测试PyTest观察/动作空间一致性、奖励函数正确性python/tests/ 目录

10.2 确定性测试

确定性仿真核心使得一个强大的测试模式成为可能:录制回放测试。记录一段输入序列 → 在浏览器中运行 Sim → 在服务器中运行 Sim → 在无头环境中运行 Sim → 断言三者产生的所有事件流完全一致(位级比对)。

十一、工程哲学

确定性即架构

确定性不是事后优化的特性,而是中心架构约束。每个设计决策——从模块边界到实体迭代顺序——都服务于"同一代码在三个上下文中的行为完全一致"这一需求。

过程化即效率

通过运行时代码生成纹理、图标、音效、建筑和世界几何体,项目避免了传统 MMO 500MB+ 的资源包,实现了几乎无限的变化,并大幅降低了客户端带宽需求。

单一真相源

代码库强制执行多个"一处定义"规则:recalcPlayerStats() 是角色属性的唯一计算位置,types.ts 是所有调优常量的唯一来源,tick() 是整个游戏循环的唯一入口。

永不信任客户端

服务器在将每个输入字段传给 Sim 方法之前进行验证。这不是安全剧场——这是让游戏在无服务器入侵的情况下无法作弊的架构基础。

十二、技术栈参考表

技术版本用途
TypeScript5.5整个代码库语言
Vite8.0开发服务器, HMR, 生产打包
Three.jsr1653D 渲染引擎
n8ao1.10.1GPU SSAO (环境光遮蔽)
postprocessing6.36.0Bloom, 色调映射, 后处理特效
ws8.21.0WebSocket 服务器 + 客户端
pg8.21.0PostgreSQL 客户端
esbuild0.28.1服务器打包器
obscenity0.4.6用户名 + 聊天脏话过滤器
Vitest4.1.8单元 + 集成测试
Puppeteer25.1浏览器 E2E 测试
PostgreSQL16-alpine游戏数据库
MariaDB11Wiki 数据库
Node.jsESM服务器运行时
@gltf-transform/cli4.4.03D 模型优化
强化学习PyTorchPython RL 训练 (PPO/DQN)

十三、为什么这个项目重要

  1. 它是一个真实的、可玩的 MMO——884 stars, 248 forks, 活跃的 Discord 社区,具有真正的多人持久化和游戏机制。
  2. 一套代码,三种截然不同的执行上下文——浏览器游戏、权威服务器和 RL 训练环境共享同一确定性核心,零代码修改。
  3. 过程化生成的完整展示——纹理、图标、音效、建筑、地形和世界布局全部由代码生成。唯一非代码资源是 CC0 3D 模型。
  4. 真实还原经典 WoW 机制——命中表、仇恨数学、怒气公式、经验曲线、GCD 机制、地下城布局、竞技场 Elo——全部正确实现。
  5. AI 原生开发实践——20 个 CLAUDE.md 文件教会 AI 编码代理如何在代码库中工作,RL 训练环境将游戏本身变成了 AI 研究平台。
  6. 大规模确定性设计——固定种子、固定步长、零挂钟依赖、有序实体迭代——可复现仿真设计的典范。
  7. 全面的测试覆盖——123 个 vitest 文件 + 51 个 E2E/自动化脚本,覆盖游戏的每个系统。

十四、潜在应用场景

游戏开发教育

一套完整的 MMO 实现,适合端到端学习游戏架构

强化学习研究

包含战斗、任务、经济和社交机制的复杂多智能体环境

自托管游戏服务器

为朋友或社区运行私有的类 WoW 世界

TypeScript 架构参考

具有严格模块边界约束的大型单体仓库最佳实践

过程化生成研究

生产级运行时代码生成技术——纹理/音频/建筑的完整范例

AI 代理文档

机器可读代理指令(CLAUDE.md 体系)的参考实现

免责声明:本文分析基于 levy-street/world-of-claudecraft 仓库截至 2026 年 6 月的公开代码。技术细节均来源于实际项目文件(包括 package.json、各目录 CLAUDE.md、源代码和配置文件)。本分析通过 GitHub API 完成,未克隆仓库。所有实现细节均为对已有开源代码的客观技术解读。