DreamFXLang
生成与往返

往返与等价

反编译的契约、缺口怎么显形、四层验证各自回答什么问题,以及三个"全绿也不等于对"的教训。

反编译不是便利导出,是一份契约:

  1. 任何 UNiagaraSystem 都能导出成 .dfs
  2. 导出是逐字节幂等的 —— 把导出建成资产,再导出一次,得到同一份文本;
  3. 语言表达不了的东西逐条写进文件头缺口注释,并以 DFX8xxx 报出来,绝不静默丢;
  4. Adopt 接管一个资产之前先重导出比对,对不上就拒绝。

第 3 条是全部重量所在。一个静默降级的导出器,会让你在三个月后对着一个不对劲的特效发呆。

缺口长什么样

往返缺口DFX8014

emitter 继承会被摊平:合并后的栈完整保留,但「继承自谁」这件事没了。内容不丢,链接丢。

往返缺口DFX8015

一个 emitter 上超过一个的事件处理器带不走,导出点名说明重建后收不到哪些事件。

往返缺口DFX8016

自定义 C++ stage 类(不是引擎那个通用 stage)没有 DreamFXLang 形式。

每一条都同时出现在两个地方:导出文件的头部,和构建/导出的日志里。

四层验证

命令回答什么问题
L1mirror-diff镜像的导出与原件的导出逐行相同吗?
L2mirror-diff镜像编译干净吗?
L3运行时等价夹具重建的系统模拟起来一样吗?固定步长 SimCache,逐帧粒子数
asset-diffasset-diff两个资产作为资产一致吗?反射走查事实,不经导出器

mirror-diff-NoCompile 跳过 L2(快得多,适合刚在同一次会话里建完镜像的场合)。

为什么必须有第四层

前三层里,L1 比的是同一个导出器的两份输出。导出器自己丢掉的东西,在两侧对称地丢, L1 逐字节相同,L2 照样编译干净,L3 只数粒子数也看不出来 —— 而画面是错的。

这不是假想:真实案例里 L1 逐字节相同、L3 报 exact、画面不对,根因是一个派生位 (bBindingExistsOnSource)根本不在任何导出里。所以 asset-diff 走的是另一条路: 反射走查两个资产的事实,包括编译器自己的视角(compiled 事实族),完全绕开导出器。

语料还比第五种东西

55 条语料在这之上,还比「按夹具建出来的资产」与「按其导出重建的资产」。 这一条抓的是对称丢失:文本比对两侧都丢了同一样东西,于是文本比对看不见它。

三条测量教训

一次只测一个系统。 L3 夹具一次 exec 只能测一个系统,否则同一个资产会被报成不同的东西。

没有 Determinism 的随机系统跟自己都不等。 所以 L3 用 A-vs-A 自对照先裁决可判定性: 一个自己和自己都不一致的系统,判 undecidable,而不是判 differ。

行为分歧 + 静态全绿 ⇒ 先量导数。 出生速度差整半倍那次,根因是 bFixedTickDelta 丢了 —— Settings 系统表里缺了一项。逐行 diff 只报第一处差异,所以修一处必须全量重跑。

自己量自己的内容

# 我的内容里有多少能被表达?按特性分桶
pwsh -File Plugins/DreamFX/.skill/dfx.ps1 coverage

# 把一整棵内容树导出成源码(一次 boot)
pwsh -File Plugins/DreamFX/.skill/dfx.ps1 decompile-all -Path=/Game/VFX

# L1 + L2
pwsh -File Plugins/DreamFX/.skill/dfx.ps1 mirror-diff -Path /Game/VFX

# 资产事实,不经导出器;-DumpFacts 把两侧完整事实写到 Saved/DreamFX/*.facts
pwsh -File Plugins/DreamFX/.skill/dfx.ps1 asset-diff -Path /Game/VFX -DumpFacts

asset-diff 默认会先把两侧都强制编译再比。不这么做的话,compiled 事实族报的是各自的 编译历史而不是内容 —— 那不是在比较任何东西。-NoCompile 只在诊断时用。

镜像命名空间

导出落在 Decompiled/<原目录> 命名空间:整棵树是一等源码,存盘即重建成镜像, 结构上碰不到原资产。展开在 Export 与 Adopt

本页目录