Card Game Engine
Card Game Engine 是一个可扩展、插件化、事件驱动的卡牌游戏引擎核心,使用 Node.js + TypeScript 实现。
引擎核心本身不包含任何具体游戏规则,所有规则、动作、事件处理都通过 Plugin 注入。Engine 只提供通用能力:状态管理、卡牌、牌堆、玩家、区域、动作、规则、事件、回合、组合、快照、回放、状态校验。
核心能力
| 能力 | 说明 |
|---|---|
| 不可变状态 | 通过 stateUtils.* 进行结构性更新,每次更新 version + 1 |
| Action 驱动 | 所有状态变更由 Action 触发,再由 ActionHandler 翻译为 { state, events } |
| 规则引擎 | RuleEngine 按注册顺序短路校验,拒绝时 state 不变 |
| 事件总线 | EventBus 同步派发事件,支持通配订阅 |
| 插件系统 | GamePlugin 把 Rule / ActionHandler / EventHandler 与可选 setup 打包注册 |
| 确定性回放 | SeededRandomProvider + 相同动作序列 → 相同终态 |
| 状态快照 | createSnapshot / restoreSnapshot,基于深拷贝隔离 |
| 状态校验 | StateValidator 内置不变量 + addStateCheck 注册游戏专属检查 |
| Server Runtime | 可选的 Koa HTTP + Socket.IO WebSocket 服务运行时(Phase 6) |
内置插件
| 插件 | 说明 |
|---|---|
StandardDeckPlugin | 标准 52 张 French deck + SHUFFLE action |
TurnPlugin | 按座位顺序轮转,支持反向 (direction = -1) |
DrawPlugin | 处理 DRAW_CARD,支持弃牌堆自动洗回 |
SimpleGamePlugin | 最简 2 人游戏,第一个清空手牌者胜 |
PokerRulesPlugin | 把通用 combination 系统以 variable 注入 state |
UnoPlugin | 完整 UNO 规则(108 张牌 + Skip/Reverse/Draw2/Wild/Draw4) |
DoudizhuPlugin | 完整斗地主规则(54 张牌 + 13 种牌型 + 叫/抢地主 + 炸弹/火箭倍率) |
UNO 与斗地主的详细 API 由各自子模块的文档提供,本站仅作概要引用。
架构概览
GameEngine
├── GameState 不可变状态(cards / zones / players / variables / version)
├── Action 玩家或插件发起的意图
├── ActionExecutor Action → { state, events } 纯函数
├── RuleEngine Action 执行前的合法性校验
├── EventBus 发布已发生的事件
├── PluginManager 插件注册与生命周期
├── ActionQueue 防递归 dispatch,受 maxActionsPerTick 限制
├── StateValidator 状态不变量校验
├── ActionHistory 有序记录已执行动作,支持回放
├── GameSnapshot 状态快照
├── ReplayEngine 基于 (initialState, actionHistory) 确定性回放
└── RandomProvider 随机源抽象(MathRandomProvider / SeededRandomProvider)设计要点
- Engine 不知道游戏规则 — 任何游戏专属逻辑都不在 Engine 出现,全部交给 Plugin
- 不可变 State — Plugin 无法直接修改
engine.state,必须通过stateUtils.*或 GameContext mutation primitive - Action ≠ Event — Action 是"我要做什么",Event 是"已经发生了什么";Action 触发 Event,Event 处理器可再触发新的 Action
- ActionQueue 防递归 — EventHandler 内
ctx.dispatch的新动作进队尾而非递归栈 - Plugin 隔离 — Plugin 通过
GameContext与 Engine 交互,不直接拿到engine引用 - 确定性可回放 — 所有随机决策必须经
ctx.random