外观
Kismet 直译模拟器:设计与心得
这套东西的起因很简单:想要一个本地对局模拟器来训练 AI, 而 KARDS 的卡牌逻辑全在客户端蓝图里,只有游戏本体能跑。
于是有两条路:读卡面文字猜效果,或者把蓝图逻辑搬出来。 第一条路试过,放弃了;第二条路做通了。
这一组文章记的是第二条路上的设计决策、踩过的坑、以及事后看当初哪里想错了。
目录
| 章 | 内容 |
|---|---|
| 01 · 为什么是 AST,不是伪代码 | 反编译产物是有损的,AST 是无损的;以及为什么文本解析这条路必然失败 |
| 02 · 架构与调用约定 | {接收者, 实参...} 的约定、两个返回值通道、接收者怎么判定、out/in 四级回退 |
| 03 · 触发点体系 | 游戏自己就有"何时发/谁响应/什么顺序";Intel 全链路的三层误判复盘 |
| 04 · 审计方法论 | 五层审计为什么必须互相打架;静态覆盖是怎么说谎的 |
| 05 · 坑与复盘 | 十二个静默错误清单,以及它们为什么编译能过 |
| 06 · 宿主该切在哪一层 | 推荐 hook 点:分派顺序、该 hook 的六类、明确不要 hook 的五条反例 |
| 07 · 发射器与运行时 | 实现特性:out 是 in-out、判定结果要入库、按来源记账、改发射器后的回归清单 |
一句话结论
如果只记一句
这套系统里最危险的不是崩溃,是"编译通过、跑得动、数字是错的"。 所有真正的 bug 都是静默的,所以能失败的断言比能跑通的程序重要得多。
数字
| 指标 | 值 |
|---|---|
| 直译产物 | 1671 个资产 · 6434 个函数 · 45.6 万行 · 21 MB |
| 手工代码 | 41 个 .cs 文件(运行时 + hook 缝 + 引擎 + 审计工具) |
| 宿主原语 | 172 个条目(真正改 GameState 的叶子 + 库函数钩子) |
| 触发点 | 68 个枚举值,卡牌实际注册 61 个,引擎全部会发 |
| 机制断言 | 153 条(--mode tests),全绿 |
| 审计模式 | 9 个(apicheck / smoke / triggers / triggerhits / rules / paramaudit / byref / repro1 / decks) |
| 自对弈 | 用社区推荐卡组跑 100 局:0 异常 / 0 卡死 / 0 非法动作 / 0% 未实现调用 |
对比一下工作量分布:1671 个资产是机器转译的,172 个原语条目是手写的。 把"要手写多少"从"每个游戏函数都要重写"压到"只写碰 GameState 的叶子", 是这套架构的全部价值。
要不要照抄这套做法
适用:逻辑在蓝图里、想要一个可复现的无头环境(AI 训练、批量平衡性实验、 协议研究的服务端侧结算)。
先决条件有三条,缺一条都别急着写发射器:
- 能拿到 AST(UAssetAPI 的
KismetExpression[]),而不是伪代码文本; - 源数据的边界是对的(01 里那个
EX_ComputedJump的教训: 反编译器切错块,直译质量直接打折); - 接受产物不可读 —— 它的目标是正确执行,不是给人看。
如果只是想批量改个常量、看看某个蓝图长什么样,用 KismetDecompiler / KismetReactor 就够了。