news 2026/10/20 2:18:52

7、【MOD开发】【骑砍2】跨平台MOD构建环境(七)/:参考程序集 vs 运行程序集——两套 DLL 的分工

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
7、【MOD开发】【骑砍2】跨平台MOD构建环境(七)/:参考程序集 vs 运行程序集——两套 DLL 的分工

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

7、【MOD开发】【骑砍2】跨平台MOD构建环境(七)/:参考程序集 vs 运行程序集——两套 DLL 的分工

背景

上篇 【MOD开发】【骑砍2】跨平台MOD构建环境(六)/:DLL 里到底装了什么——元数据、IL 与 JIT 把几个底层概念拆开了:DLL 是容器,元数据描述 API,IL 描述方法体,JIT 在运行时把 IL 编译成机器码。

这一篇回到构建环境里最常遇到的一对概念:参考程序集与运行程序集。它们经常同名、同样是.dll,但内容、用途、出现的位置都不一样。第二篇已经介绍过参考程序集,这一篇把两者的分工讲透,并和GamePath、<Private>false</Private>、元数据工具对应起来。


骑砍2

🎯 一句话区分

  • 运行程序集:元数据 + IL + 资源,能真正跑起来;游戏安装目录里的 DLL。
  • 参考程序集:只有元数据(公开 API),方法体被剥离/替换成占位,不能运行;NuGet refs / targeting pack。
  • 两者都是.dll;区别在内容,不在扩展名。

🏃 运行程序集:真正跑起来的 DLL

运行程序集(也叫实现程序集,implementation assembly)就是游戏运行时真正加载的 DLL。它包含:

  • 元数据:类型、成员、签名、特性、引用;
  • IL:每个方法的具体指令;
  • 资源:字符串、图片等。

在 Windows 上,它们通常位于:

<游戏安装目录>/bin/Win64_Shipping_Client/*.dll <游戏安装目录>/Modules/<模块>/bin/Win64_Shipping_Client/*.dll

游戏启动、加载模块、调用某个方法时,CLR/JIT 会读这些 DLL 里的 IL,把它编译成当前 CPU 的机器码。运行程序集是 JIT 的输入。

我们自己编译出来的 MOD DLL 也是运行程序集:它包含 IL,会被游戏加载,再由 JIT 编译执行。


📇 参考程序集:只给编译器看的 DLL

参考程序集(reference assembly)是专门给编译器用的 DLL。它通常来自:

  • NuGet 包,例如bannerlord.referenceassemblies.*;
  • .NET 的 targeting pack / reference pack;
  • 构建环境自己装配出来的“伪游戏目录”。

它只保留公开 API 的元数据:

  • 有哪些类型、成员、签名;
  • 哪些是 public / protected;
  • 方法参数和返回类型是什么。

方法体被剥离或替换成不可执行的占位(不同工具产物略有差异),所以它:

  • 不能运行;
  • 通常比运行程序集小很多;
  • 不需要加载依赖就能被读取。

在这套环境里,参考程序集通常放在:

vendor/game-refs/<游戏版本>/bin/Win64_Shipping_Client/*.dll output/refs/<游戏版本>/bin/Win64_Shipping_Client/*.dll

注意:它们和游戏安装目录里的运行程序集同名(比如都叫TaleWorlds.Core.dll),但来源和内容不同,不能混用。


🆚 对比表

维度参考程序集运行程序集
用途编译期运行期
内容元数据(公开 API)元数据 + IL + 资源
方法体无 / 占位有 IL
能否运行不能能
来源NuGet refs / targeting pack游戏安装目录 / 发布包
大小小大
喂给谁编译器CLR / JIT

🍽 一个类比:菜单 vs 完整菜谱

把程序集想成一本菜谱:

  • 参考程序集= 菜单:有哪些菜、配料表、价格;编译器只需要知道“有没有这道菜、参数是什么”。
  • 运行程序集= 完整菜谱 + 厨房:真正做菜时要看做法;运行时才需要 IL。

也可以类比成 C/C++ 的“头文件 vs 实现”,但要注意:C# 的参考程序集仍然是程序集(有元数据、有 PE 结构),不是纯文本头文件。类比只是为了帮助理解“声明与实现分离”。


🧠 为什么编译用参考程序集

编译器做类型检查,只需要“类型和成员的签名”,不需要方法体。用参考程序集至少有几个好处:

  1. 快:不用加载依赖,也不用解析 IL;
  2. 干净:只暴露公开 API,不会让代码意外依赖私有实现;
  3. 版本清晰:编译期对着哪个版本的 refs,就检查哪个版本的 API;
  4. 跨版本:换游戏版本时,换一套 refs 重新编译即可,不用把整个游戏装到构建机;
  5. 避免“假通过”:不会因为旧的运行程序集被复制进bin/,而用旧 DLL 编新代码。

这里要特别提<Private>false</Private>:它让游戏 DLL 引用不复制到工程的bin/。如果复制了旧的运行程序集,编译器可能拿它当引用来源,于是“用旧 DLL 编新代码”也能通过,真实的 API 变更就被掩盖了。参考程序集本身也不应该被复制进 MOD 输出——它只是编译期的“合同”。

一句话:编译看合同(参考程序集),运行看实现(运行程序集)。


🛠 在这套构建环境里怎么对应

把前面的概念落到这套构建环境里:

环节用哪套 DLL说明
编译参考程序集-p:GamePath=<refs>/指向“伪游戏目录”
引用复制不复制<Private>false</Private>避免旧 DLL 进bin/
元数据查询参考程序集第五篇的meta.sh只读元数据,不需要 IL
运行运行程序集游戏加载自己的 DLL,再 JIT 编译
MOD 产物运行程序集我们编译出的 DLL 也含 IL,由游戏加载并 JIT

用一张图表示:

编译期 参考程序集(元数据) │ 编译器 ▼ Mod.dll(元数据 + IL) 运行期 游戏运行程序集(元数据 + IL) ┐ ├─ CLR / JIT ──► 机器码 Mod.dll(元数据 + IL) ┘

MOD DLL 在编译时引用的是参考程序集的“身份”(程序集名、版本、类型签名);运行时,游戏提供同名的运行程序集,JIT 再把双方的 IL 编译成机器码。


🔍 怎么自己验证

想确认一份 DLL 是参考程序集还是运行程序集,可以看几个地方:

  1. 看大小:参考程序集通常明显更小;
  2. 看方法体:用 ILSpy / ildasm 打开,运行程序集能看到 IL,参考程序集没有方法体或只有占位;
  3. 看来源:vendor/game-refs/<ver>、output/refs/<ver>下的是 refs;游戏安装目录bin/Win64_Shipping_Client下的是运行程序集;
  4. 看特性:有些参考程序集带[assembly: ReferenceAssembly],但不是所有都有;
  5. 用元数据工具:meta.sh只读元数据,两套都能读;它看到的是 API,不是行为。

⚠️ 常见误区

  • “参考程序集不是 DLL”:不对,它也是 DLL,只是被裁剪过。
  • “DLL 一定可执行”:不对,参考程序集就不能运行。
  • “运行时也需要参考程序集”:不需要;运行时用游戏自己的运行程序集。
  • “编译必须用运行程序集”:不一定;参考程序集就是专门给编译器用的。
  • “同名 DLL 就是同一个”:不对;同名但来源不同,内容可能完全不同。
  • “用 refs 编译,运行时就不用管版本了”:不对;运行时必须提供匹配的运行程序集,API 变更仍可能导致运行期问题。

📌 本篇小结

  • 运行程序集 = 元数据 + IL + 资源,能运行;游戏安装目录里的 DLL。
  • 参考程序集 = 只有元数据(公开 API),方法体剥离/占位,不能运行;NuGet refs / targeting pack。
  • 两者都是.dll;同名不同源,区别在内容。
  • 编译用参考程序集,运行用运行程序集;GamePath指向 refs,<Private>false</Private>避免旧 DLL 复制进bin/。
  • 元数据工具只读元数据,所以用参考程序集就够了。

一句话记忆:编译看参考程序集,运行用运行程序集;同名不同源,都是 DLL。

到这里,DLL、元数据、IL、JIT、参考程序集、运行程序集这条概念链就闭合了。后面如果再展开崩溃日志判读、产物部署、跨版本移植复盘,这些概念会一直用得上。


OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 2:18:43

腾讯下场,推出股票分析智能体

最近一周AI科技圈又发生了啥新鲜事&#xff1f; Manifold AI推出WorldScape RSI机器人自我改进框架 通过内外两层智能体协作&#xff0c;WorldScape RSI将任务执行、经验复盘、技能修订与动作模型训练连接起来&#xff0c;并在RoboDojo机器人学习基准的Agent赛道登顶。内层根据…

作者头像 李华
网站建设 2026/10/20 2:18:07

PS教程初中高158节:图层蒙版+通道抠图+人像精修+3D文字全套

资源概览 这套Photoshop教程资源是一套结构清晰的系统性学习材料&#xff0c;按照初级、中级、高级三个阶段进行划分&#xff0c;共计158个mp4格式的教学视频&#xff0c;并附带了完整的配套素材文件。无论你是刚接触图像的初学者&#xff0c;还是需要提升技能的设计爱好者&am…

作者头像 李华
网站建设 2026/10/20 2:17:24

2026昌吉软件检测第三方公司排行榜TOP5:软件检测+功能性能测试+信息安全测评+软件验收报告 机构地址及联系方式推荐

昌吉市软件检测机构林立如云&#xff0c;良莠不齐之势显而易见。为助本地开发者、政务单位及中小企客户拨云见日、择善而从&#xff0c;小编历时三周实地踏勘&#xff0c;走访二十余处办公点位&#xff0c;核查资质原件、比对检测案例、暗访服务流程&#xff0c;最终甄选出五家…

作者头像 李华
网站建设 2026/10/20 2:17:05

JSONP协议误用导致的数据泄露原理与治理方案

1. 这不是“劫持”&#xff0c;而是一场被遗忘的协议误用事故“JSONP劫持”这个词在安全圈里流传多年&#xff0c;但说实话&#xff0c;我第一次在某次红队复盘会上听到它时&#xff0c;心里咯噔一下——不是因为多高深&#xff0c;而是因为它背后藏着一个典型的“技术债陷阱”…

作者头像 李华
网站建设 2026/10/20 2:15:02

基于Python的CNN迁移学习实现夏冬季节风景图像分类实战

又是毕设季节。看到“基于Python的卷积神经网络训练识别夏冬季节风景”这个题目&#xff0c;我第一反应是&#xff1a;典型但确实有得做。说它典型&#xff0c;是因为它本质上是图像二分类&#xff0c;夏季和冬季&#xff0c;两个标签&#xff0c;网络结构不用太复杂&#xff1…

作者头像 李华
网站建设 2026/10/20 2:14:49

d3dx10_36.dll丢失怎么修复?官方运行库安装详解

启动游戏&#xff0c;双击图标&#xff0c;屏幕先黑一下&#xff0c;随后弹出一个提示&#xff1a;由于找不到 d3dx10_36.dll&#xff0c;无法继续执行代码。这个画面在过去十几年里反复出现&#xff0c;尤其是在各种单机游戏和三维设计软件上&#xff0c;几乎成了“运行环境不…

作者头像 李华