资产引用门禁:字符串Contains不能代表包目录归属
自动关联目录:资产引用门禁:字符串Contains不能代表包目录归属
核心判断:UE 资产引用规则判断的是“源包通过哪类依赖边指向哪个目标包”。对路径做
Contains只能判断字符出现过,不能证明目录归属,更不能说明依赖语义。
一、业务问题:内容分层必须在提交前阻断反向引用
运行时公共资产、玩法内容、编辑器资源和可选内容通常有不同装载边界。一个不该出现的硬引用可能扩大 Cook 集合或让运行目标携带多余资源,因此需要批量扫描并输出可修复报告。
二、实际实现:工具方向正确,规则匹配过于宽松
实际检查器从 JSON 读取扫描路径、递归开关、类型限制、忽略目录、黑名单和白名单;通过 Asset Registry 枚举资产,再查询硬依赖并生成 CSV。把规则外置、使用包依赖图而不是加载 UObject、支持按目录和类型缩小工作集,这些都值得保留。
核心缺陷是所有范围判断都使用字符串子串:忽略路径匹配 ObjectPath,黑白名单匹配依赖包名。于是 /Game/Common 也会命中 /Game/CommonExperimental,短片段可能命中包名中部;白名单一旦子串命中,就直接跳过后续黑名单。与此同时,代码只检查 Hard 依赖,读取了 Referencer 却未使用,报告也没有保存命中的规则、依赖类别或规则版本。直接用逗号拼 CSV,还会让含特殊字符的字段破坏列结构。
三、目标方案:先编译规则,再逐条判定依赖边
struct FReferenceEdge {
FName SourcePackage;
FName TargetPackage;
EDependencyCategory Category;
EDependencyProperty Properties;
};
bool IsUnderRoot(FStringView Package, FStringView Root) {
Package = NormalizeLongPackageName(Package);
Root = TrimTrailingSlash(NormalizeLongPackageName(Root));
return Package == Root || Package.StartsWith(Root + TEXT("/"));
}
FDecision Evaluate(const FReferenceEdge& Edge, const FCompiledRules& Rules) {
auto Matches = Rules.MatchBySegments(Edge.SourcePackage,
Edge.TargetPackage,
Edge.Category);
return ResolveExplicitPrecedence(Matches); // deny / allow / no-rule / conflict
}配置加载时先验证 Long Package Name、规范大小写和尾斜杠,并把目录规则编译成按段匹配的前缀树。规则要显式声明 Hard、Soft、SearchableName 或 Manage 等类别,不再默认“只看 Hard 就代表全部”。如果白名单和黑名单同时命中,应按规则优先级裁决或报告配置冲突,不能依赖数组遍历顺序。
输出记录至少包含源包、目标包、边类别、命中规则、规则版本和建议修复方向;结构化 JSON 作为权威结果,CSV 只是正确转义后的视图。
四、边界与验证
Asset Registry 依赖图适合证明静态包关系,但不能覆盖运行时字符串加载、外部文件或脚本动态拼接路径;这些入口需要单独的 API 约束和运行时观测。反过来,也不能因为静态图不完整就放弃它:硬引用门禁仍能在 Cook 前阻止一大类确定性问题。
测试必须包含相似前缀目录、路径片段出现在包名中部、大小写与尾斜杠、对象路径和包路径混用、重定向、插件挂载点、循环依赖、不同边类别、黑白规则冲突和 CSV 特殊字符。
五、反思
现有工具已经抓住了正确切入点:用 Asset Registry 做离线依赖检查。需要批判的是规则层把 UE 包身份退化成了字符串搜索。门禁的价值不在于“扫出一些结果”,而在于同一条依赖边在任何机器、任何规则顺序下都得到同一个可解释裁决。