NMS 模组工具

NMS 模组工具

NMS Mod Tool 是一个 Windows 桌面应用程序,用于修改《无人深空》,基于 .NET 10 / WPF MVVM 构建。它封装了 libMBIN(MBINCompiler 背后的库),为提取、反编译、编辑、重新编译和部署模组提供图形化工作流程。

NMS Mod Tool v1.0.3

NMS Mod Tool 是一款用于修改《无人深空》的 Windows 桌面应用程序,基于 .NET 10 / WPF MVVM 构建。它封装了 libMBIN(MBINCompiler 背后的库),为提取、反编译、编辑、重新编译和部署模组提供了图形化工作流程。

它是 Tub0Crisco 所开发的 NMS Modding Station 的精神继承者,是一次旨在使工作流程与当前模组制作方法保持同步的现代化重写。

要求: 必须安装 .NET 10 桌面运行时(Windows 桌面运行时 10.0+)。

本项目依赖于 monkeyman192 开发的 libMBIN,这是用于反编译和重新编译 NMS .MBIN 文件的核心库。该库将在首次启动时自动下载。

引言

概述

《无人深空》将其游戏数据存储在包含 .MBIN 编译二进制文件的 .PAK 存档中。模组制作涉及提取这些存档,将二进制 .MBIN 文件反编译为可编辑的 XML,进行修改,然后重新编译回 .MBIN

模组以松散文件目录的形式部署——游戏直接从 GAMEDATA\MODS 加载它们,无需重新打包 .PAK 存档。

NMS Mod Tool 通过双标签界面简化了这一工作流程:

  • 已解包文件 - 浏览提取的游戏文件,将它们复制到项目中,反编译/重新编译 .MBIN <-> .MXML
  • 模组项目 - 管理模组项目,编辑项目设置,部署完成的模组

先决条件

  • 通过 Steam、GOG Galaxy 或 Game Pass 安装的**《无人深空》**
  • 磁盘上有已解包的游戏文件(使用 提取 -> 解包游戏文件 或手动解包)

运行时需要 libMBIN.dll。如果启动应用时缺少该文件,系统会提示您下载——应用会自动从 GitHub 获取并立即加载。

用户指南

本部分将介绍 NMS Mod Tool 的功能、使用方法以及设置面板中每个选项的含义。如果您只想提取文件并制作模组,可以跳过本部分之后的阅读。

开始使用

典型的首次设置

如果您乐于将 UnpackedProjects 文件夹保留在应用程序目录中,这是一种快速的入门方式:

  1. 打开 工具 -> 设置,点击 重置为默认值。这会将 已解包 -> [应用目录]\Unpacked,项目 -> [应用目录]\Projects,并清除游戏路径。
  2. 仍在设置中,点击 自动检测。应用程序会探测您系统中的《无人深空》安装,并自动填入 PCBANKS模组部署 路径。
  3. 点击 确定 保存。

如果您希望将提取的文件和模组项目保存在其他位置,请手动设置这些路径——请参阅下表。

自动检测路径

转到 工具 -> 设置 并点击 自动检测。应用程序通过以下方式探测您系统中的《无人深空》安装:

  • Steam 注册表项 + libraryfolders.vdf(查找所有 Steam 库驱动器)
  • GOG Galaxy 注册表项
  • Game Pass 包目录
  • 常见的 GOG 安装路径作为后备方案

如果发现多个安装,将出现一个选择器让您选择。PCBANKS模组部署 路径将自动填入。

或者,手动设置它们:

  • 已解包游戏文件路径 – 提取的 .PAK 内容所在位置
  • 模组项目路径 – 您的模组项目文件夹的存储位置
  • PCBANKS 路径 – 指向您游戏的 GAMEDATA\PCBANKS 目录
  • 模组部署路径 – 完成模组的部署位置

如果您想重新开始,这里也提供 重置为默认值 选项——它将 已解包 -> [应用目录]\Unpacked,项目 -> [应用目录]\Projects,并清除游戏路径。

键盘快捷键

  • Ctrl+Q – 退出
  • Ctrl+, – 打开设置
  • Ctrl+Shift+D – 清理目标
  • Ctrl+E – 解包游戏文件
  • Ctrl+Shift+S – 选择要提取的 PAK 文件
  • Ctrl+P – 编辑当前项目
  • Ctrl+Shift+P – 设置当前项目
  • Ctrl+N – 创建新项目(模组项目)
  • Ctrl+Shift+N – 创建新文件夹(模组项目)
  • Ctrl+Shift+C – 复制到项目路径(已解包)
  • Ctrl+Shift+E – 在文件资源管理器中打开
  • Ctrl+Shift+I – 安装选定的模组
  • F2 – 重命名(模组项目)
  • F5 – 刷新
  • F6 – 重新编译(模组项目)
  • Alt+Home – 返回主页
  • Back – 返回上一级
  • Delete – 删除(上下文菜单)

设置参考

工具 -> 设置 下可用的每个选项都列在这里,并附有默认值及其功能说明。

  • 已解包游戏文件路径 (默认:[应用目录]\Unpacked – 提取的 .PAK 内容所在位置
  • 模组项目路径 (默认:[应用目录]\Projects – 您的模组项目文件夹的存储位置
  • PCBANKS 路径 (默认:- – 指向您游戏的 GAMEDATA\PCBANKS 目录
  • 模组部署路径 (默认:- – 完成模组的部署位置
  • 文本编辑器路径 (默认:- – 用于从应用程序打开 .MXML/.EXML/文本文件的可执行文件
  • 解包游戏文件为大写 (默认: – 选中后,提取的路径将转为大写。与其他模组制作工具使用的约定一致。取消选中以保留原始 PAK 大小写。
  • 已解包只读 (默认: – 隐藏文件浏览器上下文菜单中提取文件的删除选项。防止意外删除您提取的游戏数据。
  • 验证 PAK 哈希 (默认: – 使用增量提取时,时间戳和大小与清单匹配的 PAK 将通过 xxHash64 进行验证。可捕获 PAK 被替换为大小和时间戳相同但内容不同的极端情况。哈希计算与提取并发进行。
  • 启用提取分析器 (默认: – 将每个 PAK 的时间分解写入 %LOCALAPPDATA%\NMSModTool 中的 extraction_profile.json。有助于诊断提取缓慢的问题。
  • 定期更新检查 (默认: – 启动时,每个间隔检查一次 GitHub 以获取更新的 libMBIN 版本。
  • 定期更新间隔 (默认:24 小时 – 检查 libMBIN 更新的频率。

解包游戏文件

提取 -> 清理目标 会从您的已解包游戏文件目录中删除所有提取的文件并重置提取清单。当您希望下次运行时进行已知良好的完整提取,或想通过删除以前提取的数据来释放磁盘空间时,请使用此选项。

提取 -> 解包游戏文件 会将 PCBANKS 中的所有 .PAK 文件提取到您的已解包游戏文件目录。

提取 -> 选择要提取的 PAK 文件 会打开一个可搜索的对话框,您可以在其中选择单独提取的 .PAK 文件,而不是提取所有内容。对话框显示所有带复选框、文件大小和日期的 PAK。使用搜索框按名称过滤,并使用全选/取消全选进行批量切换。当目标中已有文件时,仍会显示清理提示——选择“清理”先删除所有内容,或选择“否”直接提取(覆盖冲突文件)。

如果目标中已包含提取的文件,对话框会询问是清理目标还是继续:

  • 解包游戏文件 - 跳过清理会触发增量提取(有关基于清单的变化检测工作原理,请参阅技术信息中的增量提取)。

  • 选择要提取的 PAK 文件 - 跳过清理会直接提取所选文件,覆盖任何冲突文件。

  • 清理 - 在提取前删除所有现有文件。当您想要已知良好的完整提取时使用此选项。

  • 跳过清理 - 只重新提取时间戳、大小或哈希与上次运行不同的 PAK。有关工作原理,请参阅技术信息中的清单部分。

提取过程中,状态栏会显示完成百分比最低的活动 PAK。整体进度条反映所有 PAK 的聚合情况。

提取完成后,完成对话框会显示提取了多少文件、失败了多少(附示例)以及创建了多少目录。失败的文件也会写入日志;如果您想调查,请检查 extraction_profile.json

模组项目

创建模组项目

切换到 模组项目 标签。在根文件夹中,右键单击并选择 创建新项目 以创建新模组,或选择现有文件夹并使用 设为当前项目 将其选中。

双击文件夹可导航进入并尝试自动加载项目设置。

编辑项目设置

设置当前项目后,项目 -> 编辑当前项目(或右键单击 -> 编辑项目)将打开项目设置对话框。您可以在其中编辑项目的元数据(名称、作者、版本、描述、支持的游戏版本等)。

将文件复制到项目中

已解包文件 标签中,右键单击文件或目录并选择 复制到项目路径(需要先设置当前项目)。

文件名包含 GLOBALS.GLOBAL 的文件将自动路由到项目内的 GLOBALS\ 子目录中。某些文件类型生成 .MXML(完整的 XML 替换),而其他类型生成 .EXML(补丁格式)——有关详细信息,请参阅下面的文件格式规则部分。

文件夹操作

模组项目 标签中的右键上下文菜单支持:

  • 创建新文件夹 (Ctrl+Shift+N)
  • 创建新项目 (Ctrl+N)
  • 重命名 (F2)
  • 删除 (Delete)
  • 设为当前项目
  • 编辑项目
  • 重新编译 (F6,针对 .MXML 文件)
  • 安装选定的模组 (Ctrl+Shift+I)
  • 打开模组文件夹
  • 在文件资源管理器中打开 (Ctrl+Shift+E)

编辑与重新编译

  • .MXML 文件可以通过右键单击 -> 重新编译(仅在模组项目标签中为 .MXML 文件显示)重新编译回 .MBIN
  • .EXML 文件是补丁文件,永远不会直接重新编译
  • 使用您喜欢的文本编辑器(在设置中设置)进行更改

文件格式规则

  • .MBIN – 编译的游戏二进制文件 (可重新编译:否——请先反编译)
  • .MXML – 来自关键目录的完整 XML 替换 (可重新编译:是)
  • .EXML – 所有其他文件的补丁 XML (可重新编译:从不)

为什么有两种格式?

世界第二部分 更新以来,MBINCompiler 输出 .MXML——这是 Hello Games 工具内部使用的原生 XML 格式。游戏的松散文件加载器期望的是 .EXML 文件。当您将文件复制到项目时,应用程序会为关键目录保留 .MXML(这些目录需要完整的往返保真度),并将其他所有内容重命名为 .EXML(补丁格式)。两种格式包含相同的 XML 内容——扩展名的不同告诉游戏如何应用该文件。

有关生成 .MXML 的七种目录类型,请参阅技术信息中的文件格式规则部分。

部署模组

模组项目 标签中右键单击项目文件夹,选择 安装选定的模组。模组文件夹将作为松散文件复制到您的模组部署路径(GAMEDATA\MODS)。无需重新打包 .PAK 文件。

游戏直接加载 GAMEDATA\MODS 的内容,因此部署的模组将在下次游戏启动时生效。

故障排除

  • "libMBIN.dll 未找到" - 应用程序应自动提示下载。如果没有,请从 MBINCompiler releases 下载并将其放置在可执行文件旁边。
  • 标签中没有文件显示 - 请验证 工具 -> 设置 -> 自动检测 中的路径设置,或手动设置。
  • 重新编译失败 - 检查 .MXML 文件是否为有效的 XML,并与目标 .MBIN 的预期模式匹配。
  • 自动检测未找到任何内容 - 确保已安装《无人深空》。应用程序会在游戏根目录中检查 GAMEDATA\PCBANKS。如果检测失败,请在 工具 -> 设置 中手动设置路径。
  • 增量提取显示未更改但目标不正确 - 清单以 PAK 身份为键。删除 %LOCALAPPDATA%\NMSModTool\pak_manifest.json 以强制下次运行时完全重新提取。

技术信息

本部分记录了应用程序的内部工作原理:提取引擎、缓存大小、增量提取算法、文件格式规则以及运行时/构建架构。只想制作模组的最终用户可以跳过本部分。

提取引擎

提取在两个并发层中进行:

跨 PAK - 并发(CPU-2,限制为同时处理 2-8 个 PAK)。 动态 SemaphoreSlim 门控并行 Task.Run 工作线程。每个工作线程独立处理一个 PAK,因此多个 CPU 核心可用于解压缩和文件 I/O,而不会破坏任何单个 PAK 的缓存。

PAK 内部 - 排序顺序,单线程。 在提取开始之前,PAK 的文件条目按其存档中的存储偏移排序。这将随机查找转换为顺序读取模式,从而在 HDD 和 SSD 上最大化吞吐量。

每个 PAK 的阶段

每个 PAK 按顺序经历以下阶段:

  1. 元数据扫描 - 读取 PAK 头并构建完整文件列表
  2. 偏移排序 - 按 entries[i+1].Offset 对文件索引排序,使提取遵循物理存储顺序
  3. 路径预计算 - 清理文件路径,应用 GLOBALS 路由,预先创建所有输出目录
  4. 顺序提取 - 对 PAK 进行单次遍历:
    • 块按需解压缩到 LRU 缓存中
    • 引用相同或相邻块的连续文件命中缓存而不是重新读取
    • 每个文件通过带动态大小写入缓冲区(4 KB-256 KB,按条目大小缩放)的 FileStream 写入磁盘;<= 100 MB 的文件通过容量为 8 的专用 I/O 写入通道,将解压缩与系统调用分离
    • 进度按 PAK 内的文件报告
    • PAK 的 xxHash64 与提取并发计算(当启用哈希验证时),将顺序读取与提取 I/O 重叠

进度显示

提取过程中,状态栏显示一行——完成百分比最低的活动 PAK(瓶颈)。随着 PAK 完成和新 PAK 开始,显示的 PAK 自然循环。整体进度条反映所有 PAK 的聚合情况(每个 PAK 百分比之和 / PAK 总数)。

缓存大小

每 PAK 的 LRU 块缓存随可用系统内存扩展:Math.Clamp(availableGB * 256, 128, 32768) 块(最大 8 MB-2 GB)。使用排序偏移提取时,块最多被访问一次——缓存吸收同一块内相邻文件的引用。更大的缓存使性能更高的系统受益,而不会惩罚低内存系统。

增量提取

当目标中已包含文件且您跳过清理时,应用程序会执行增量提取:

  • 清单(%LOCALAPPDATA%\NMSModTool 中的 pak_manifest.json)跟踪每个 PAK 的最后写入时间戳、大小和 xxHash64 哈希
  • 阶段 1 - 时间戳或大小已更改的 PAK 将被重新提取(快速,无需哈希)
  • 阶段 2 - 时间戳和大小匹配的 PAK 通过 xxHash64 验证(捕获 PAK 被替换为大小和时间戳相同但内容不同的极端情况)
  • 可以在设置中禁用哈希检查(工具 -> 设置 -> 验证 PAK 哈希)。启用时,哈希与提取并发计算,因此在 SSD 上的额外成本可以忽略不计。
  • 未更改的 PAK 完全跳过

清单以 PAK 文件路径为键。删除它会强制下次运行时完全重新提取。

目标清理

选择清理会在提取前删除所有现有文件。清理阶段按目录报告进度,并且可以取消。

GLOBALS 路由

文件名中包含 globals 的 PAK 文件会自动提取到输出目录中的 GLOBALS\ 子文件夹中。将文件复制到模组项目时也应用相同路由。

这不是游戏严格要求的(松散文件加载器会自行解析),但它保留了其他模组制作工具使用的约定,并将全局设置与每个场景/资产内容分开。

诊断

ExtractionProfiler 默认开启。激活时,它会将每个 PAK 的时间分解写入 %LOCALAPPDATA%\NMSModTool 中的 extraction_profile.json。报告阶段为:

  • 元数据 - PAK 头读取和文件列表构建
  • 路径预计算 - 路径清理、GLOBALS 路由、输出目录创建
  • PAK 读取 - 从 PAK 文件的原始读取
  • 解压缩 - 块解压缩
  • 文件 I/O - 写入磁盘

这与状态栏报告的数据相同,持久化到磁盘以供运行后分析。

文件格式规则

七种目录类型生成 .MXML 文件(完整替换):

  1. 场景 - SCENES\
  2. 材质 - MATERIALS\
  3. 粒子 - PARTICLES\
  4. 动画 - ANIMATIONS\
  5. 描述符 - DESCRIPTORS\
  6. 几何数据 - GEOMETRY\
  7. cGcNGuiLayerData - MXML 根元素为 cGcNGuiLayerData 的文件(此模板状态性太强,不适合补丁语义,因此需要完整替换)

所有其他内容生成 .EXML 补丁。

架构

  • .NET 10 / WPF,采用 MVVM 模式
  • libMBIN 编译时引用(非基于反射);如果缺失,通过 AppDomain.AssemblyResolve 在运行时解析
  • 设置存储在 %LOCALAPPDATA%\NMSModTool\user.config(XML)中
  • PAK 更改跟踪存储在 %LOCALAPPDATA%\NMSModTool\pak_manifest.json(JSON)中
  • 提取配置文件存储在 %LOCALAPPDATA%\NMSModTool\extraction_profile.json(JSON,当分析器启用时)
  • 单文件发布;libMBIN.dll 被排除并在首次启动时自动下载

菜单布局

菜单结构的参考快照:

  • 文件 - 退出 (Ctrl+Q)
  • 工具 - 设置 (Ctrl+,)
  • 提取 - 解包游戏文件 (Ctrl+E),选择要提取的 PAK 文件 (Ctrl+Shift+S)
  • 项目 - 设置当前项目 (Ctrl+Shift+P),编辑当前项目 (Ctrl+P),最近项目
  • 帮助 - 关于,实用链接,查看 README,LibMBIN 更新

致谢

本项目基于 Tub0CriscoNMS Modding Station 的原始概念和设计模式。原始项目大约有 8 年历史。应用程序中的关于对话框也向原始作者致谢。

许可证

许可证待定 - NMS Modding Station 的原始开发者已允许发布本项目,但尚未选择最终许可证。一旦做出决定,将添加许可证。