1、【MOD开发】【骑砍2】跨平台MOD构建环境(一):总体思路与 SDK 引导

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

1、【MOD开发】【骑砍2】跨平台MOD构建环境(一):总体思路与 SDK 引导

背景

这是「跨平台 MOD 构建环境」系列的第一篇,以骑砍2(Mount & Blade II: Bannerlord)为例,讲如何在 Linux 上搭建一套通用的、跨平台的 MOD 构建环境。

骑砍2 是 Windows 平台上的游戏,它的 MOD 生态也基本围绕 Windows + Visual Studio 展开:作者发布的源码工程里,路径大小写随意、直接引用游戏本体的 DLL、打包目标写死成 Windows 专属命令。一旦在没有 Windows、也没有安装游戏本体的机器上做「编译 + 打包」,这些工程几乎无法直接跑起来。

本系列要讲的,就是把这套流程统一到几条通用命令下:自动准备 .NET SDK(Software Development Kit,软件开发工具包)、用参考程序集代替游戏本体、在只读源码之外构建、再按 Bannerlord 模块布局打包。全系列按「总体思路 → 参考程序集 → 源码同步 → 编译打包 → 元数据工具」的顺序展开,本篇先给出全局设计,并讲清最底层的一步------SDK 的引导。


骑砍2

🎯 要解决的四个问题

先把痛点摆出来,后面每一篇都对应其中一块。

维度 Windows 上的常见做法 跨平台构建环境的替代方案
编译环境 预装 Visual Studio / .NET SDK 首次运行自动引导 .NET SDK 到工作区
游戏依赖 引用本机安装的游戏 DLL 用 NuGet 参考程序集装配「伪游戏目录」
源码保护 直接在源码目录编译 复制到工作副本,源码只读
输出结构 各自 xcopy 到模块目录 描述符驱动,统一打包成模块目录 + zip

这套环境不依赖 Windows、编译期也不依赖游戏本体;运行验证仍要回到 Windows 游戏,这点会在系列里反复强调。


🗂 部件与数据流

与其绑定某一份具体目录,不如先看这套环境由哪些部件组成、数据怎么流动。

三条原则贯穿始终:

  1. 源码只读:MOD 源码目录永不被写入,所有中间产物都在独立的工作区;
  2. 描述符驱动:新增一个 MOD 只需放源码 + 写一个 JSON 描述符,脚本里没有 MOD 专属硬编码;
  3. 产物集中:工作区可整体删除重建,源码与配置不受影响。

为便于叙述,后续统一使用一套示例命名(与实际目录无关):脚本放 bin/,描述符放 config/<mod>.json,中间物用 cache/(SDK 与包缓存)、refs/(伪游戏目录)、work/(构建副本),产物落在 out/(模块目录)与 dist/*.zip(分发包),参考程序集留档在 vendor/。


🚀 一条流水线

对外只需一个主入口脚本,它把各阶段串成流水线。核心思路如下。

sh 复制代码
# build.sh:按顺序调用各阶段脚本(示例)
./sdk.sh                                     # 1. 引导 .NET SDK
REFS=$(./refs.sh "$VER" core native sandbox) # 2. 装配参考程序集,回显路径
./sync.sh "$MOD" config/$MOD.json            # 3. 同步源码副本
./compile.sh "$MOD" config/$MOD.json "$REFS" # 4. 编译
./pack.sh "$MOD" config/$MOD.json            # 5. 打包

每个阶段脚本都能单独执行,主入口只是按序调用。设计上有一个容易忽略的细节:像 refs.sh 这样的脚本用 stdout 回显关键结果(如伪游戏目录路径),用 stderr 输出日志 ,这样上层才能用命令替换 $(...) 接住返回值而不被日志污染。

这五步正好对应后面几篇:本篇讲第 1 步,第二篇讲第 2 步,第三篇讲第 3 步,第四篇讲第 4、5 步,元数据查看工具单独作为第五篇。


🖥 命令行速查

对外命令围绕主入口展开,常见用法如下。

命令 / 选项 作用
build.sh --list 列出已注册的 MOD(读 config/*.json)
build.sh --mod <id> 编译 + 打包指定 MOD 并出 zip
build.sh --mod <id> --clean 先清工作副本与产物再构建
--ref-version <ver> 覆盖参考程序集版本
--target-framework <tfm> 只编指定目标框架
--no-zip 只出模块目录,不压缩

以「列出 + 构建」为例,终端输出如下(真实输出,见截图)。


🧩 免 sudo 引导 .NET SDK

需求是:不污染系统、不需要 sudo、第一次跑就自动装上。通用做法是三级查找,优先级从高到低。

对应到脚本:先看工作区缓存里有没有可执行的 dotnet,再看系统 PATH,都没有才下载官方安装脚本。

sh 复制代码
# sdk.sh:三级查找(示例)
if [ -x "$CACHE_DIR/dotnet/dotnet" ]; then
	DOTNET_ROOT="$CACHE_DIR/dotnet"                 # ① 复用本地缓存
elif have dotnet; then
	DOTNET_ROOT=$(dirname "$(command -v dotnet)")   # ② 复用系统
else   # ③ 下载 dotnet-install.sh 安装到工作区
	bash "$installer" --channel "${DOTNET_CHANNEL:-8.0}" \
		--install-dir "$CACHE_DIR/dotnet"
	DOTNET_ROOT="$CACHE_DIR/dotnet"
fi

安装完成后把一批环境变量导出,让后续 dotnet build 子进程直接继承:

环境变量 作用
DOTNET_ROOT 指向 SDK 根目录,子进程据此定位运行时
PATH 把 DOTNET_ROOT 前置,dotnet 命令优先命中它
NUGET_PACKAGES NuGet 包缓存改到工作区,不写用户家目录
DOTNET_NOLOGO/DOTNET_CLI_TELEMETRY_OPTOUT/DOTNET_SKIP_FIRST_TIME_EXPERIENCE 关掉首启提示、遥测与首次体验,减少噪音

一句话记忆:缓存优先、系统兜底、都没有才下载,且一切写入工作区。


⚠️ 一个必须记住的坑:安装脚本要用 bash

官方安装脚本 dotnet-install.sh 内部用到了 set -o pipefail,而 pipefail 是 bash 特性,部分 sh(如 dash)并不支持。若直接用 sh dotnet-install.sh,会报类似 Illegal option -o pipefail。

sh 复制代码
# sdk.sh:优先用 bash 执行安装脚本(示例)
if have bash; then
	bash "$installer" --channel "${DOTNET_CHANNEL:-8.0}" --install-dir "$DOTNET_DIR"
else
	sh "$installer" --channel "${DOTNET_CHANNEL:-8.0}" --install-dir "$DOTNET_DIR"
fi

排查表里也记这一条:遇到 dotnet-install.sh: Illegal option -o pipefail,手动执行时同样要用 bash 而不是 sh。


📌 本篇小结

  • 跨平台构建环境解决「无 Windows / 无游戏本体也能编译打包」的问题,核心是 参考程序集 + 伪游戏目录 + 只读副本 + 描述符驱动。
  • 主入口是一条五步流水线(SDK → 参考程序集 → 源码同步 → 编译 → 打包),每步都能单独跑。
  • 引导 SDK 用三级查找实现免 sudo,并把缓存与包都锁在工作区内。
  • dotnet-install.sh 必须用 bash 执行。
  • 全系列用一套示例命名(bin/、config/、cache/、refs/、work/、out/),与具体目录无关,便于聚焦通用做法。

一句话记忆:先备好工具链与游戏依赖,再在只读源码之外完成构建与打包。

下一篇进入最关键的一环:为什么能用 NuGet 上的参考程序集代替游戏本体,以及「伪游戏目录」是怎么装配出来的。


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

【MOD开发】【骑砍2】跨平台MOD构建环境(二):参考程序集与伪游戏目录

相关推荐
霸王•吕布3 年前
骑砍战团MOD开发(39)-RTS塔防保卫卡拉迪亚大陆
游戏开发·骑马与砍杀·骑砍战团·mod开发·rts塔防·rts视角·rts游戏