资讯动态

Rimworld Mod 制作入门:从项目源码到第一个可加载补丁

发布时间:2026/10/17 16:59:12 来源:尧图企业网站定制
简介这份资源是面向Rimworld模组开发初学者与进阶爱好者的实战型项目源码包围绕Mod结构搭建、开发工具选型、程序集构建、C#代码编写与测试等核心环节展开帮助读者打通从零到可运行Mod的完整链路。包内共11个文件以cs代码文件、xml数据定义、csproj工程文件为主辅以md说明文档、html页面及gitignore等配置项压缩包约16KB体量轻巧但结构完整便于直接导入Visual Studio或JetBrains Rider进行二次开发。资源以制作一把带瘟疫效果的测试枪为案例涵盖About目录配置、Defs数据定义、Assemblies程序集、Languages本地化翻译等模块并附有反编译游戏代码的思路方便理解游戏内部逻辑。目前已有209人学习下载适合希望掌握Mod目录组织、数据驱动设计与代码调试方法的开发者参考借鉴。1. Rimworld Mod 制作从项目源码到能跑起来的第一个补丁很多人第一次打开 Rimworld 的 Mod 目录看到一堆 XML 和 DLL 混在一起第一反应是「这玩意儿能改」。我当初也是这么想的直到自己动手把游戏里一个物品的堆叠上限从 75 改成 500才发现 Rimworld 的 Mod 体系其实对新手相当友好——纯 XML 就能完成大量修改不需要写一行 C#。但问题也在这里网上教程要么只讲 XML 不讲项目源码结构要么直接甩一个 GitHub 仓库让你自己看中间缺了「怎么从零搭出一个能加载的 Mod 项目」这一步。这篇内容就是补上这一步。不管你是想做一个简单的数值调整 Mod还是准备用 Harmony 做深度补丁下面这套流程都是我实际跑通过、能复现的路径。适合有基本文件操作能力、想认真做一个 Mod 而不是随便改改的玩家和开发者。2. Rimworld Mod 的项目结构About、Assemblies、Defs 各放什么2.1 一个能加载的 Mod 最少需要哪些文件Rimworld 加载 Mod 的逻辑很直接扫描 Mod 文件夹找About/About.xml读里面的元数据然后根据packageId注册。如果这个文件缺失或格式错误游戏启动时会在日志里报错Mod 列表里根本不会出现你的条目。最小可加载结构长这样MyFirstMod/ ├── About/ │ └── About.xml ├── Defs/ │ └── ThingDefs/ │ └── MyItems.xml └── Assemblies/ 纯 XML Mod 不需要这个目录About.xml是入口必须包含以下字段?xml version1.0 encodingutf-8? ModMetaData nameMy First Mod/name authorYourName/author packageIdyourname.myfirstmod/packageId supportedVersions li1.5/li /supportedVersions description一个用于测试的简单 Mod。/description /ModMetaDatapackageId的命名规则是「作者名.模组名」全小写不能有空格。这个 ID 是唯一的后续做兼容性判断、Mod 排序、依赖声明都靠它。我见过有人用中文或大写字母结果游戏直接忽略整个 Mod日志里只给一行Invalid packageId排查起来很费时间。supportedVersions里写你实际测试过的版本。Rimworld 每次大版本更新都会改 Def 结构写错版本号可能导致游戏加载时直接崩溃。如果你只测过 1.5就只写 1.5不要为了「兼容更多」把 1.4、1.3 都塞进去。2.2 Defs 目录的组织方式与加载顺序Defs下面可以按类型建子目录比如ThingDefs、RecipeDefs、HediffDefs。游戏加载时会递归扫描Defs下所有.xml文件所以子目录名字其实不影响加载只影响你自己找文件。但有一个坑同一个 Def 类型下defName不能重复。如果你新建了一个ThingDefdefName叫Steel而原版已经有Steel游戏会报重复定义并跳过你的整个文件。常见做法是给自己的 Def 加前缀比如MyMod_Steel。如果你是想修改原版物品而不是新增不要重新定义而是用Patch或者xpath继承。一个典型的ThingDef新增物品?xml version1.0 encodingutf-8? Defs ThingDef ParentNameResourceBase defNameMyMod_AdvancedComponent/defName label高级零部件/label description用于高级制造的高级零部件。/description graphicData texPathThings/Item/Resource/AdvancedComponent/texPath graphicClassGraphic_Single/graphicClass /graphicData stackLimit500/stackLimit statBases MarketValue120/MarketValue Mass0.5/Mass /statBases thingCategories liManufactured/li /thingCategories /ThingDef /DefsParentNameResourceBase是关键。Rimworld 的 Def 系统支持继承ResourceBase是原版定义的一个抽象模板包含了资源类物品的通用字段比如selectable、category、drawerType。继承它之后你只需要写差异部分不用从零拼一个完整的ThingDef。如果不写ParentName游戏会要求你补全所有必填字段漏一个就报错。texPath指向的是Textures目录下的路径不带扩展名。Rimworld 会自动找.png。如果你没有自己的贴图可以直接引用原版的路径比如Things/Item/Resource/Component这样至少不会出现紫色方块。stackLimit就是堆叠上限原版零部件是 75这里改成 500。这个字段在ThingDef里是可选覆盖继承自ResourceBase的默认值会被你写的值替换。2.3 用 Harmony 做 C# 补丁时 Assemblies 怎么放当你需要修改游戏逻辑而不是单纯改数值时就需要写 C# 并编译成 DLL放进Assemblies目录。Rimworld 使用 Harmony 作为运行时补丁库你的 DLL 需要引用0Harmony.dll、Assembly-CSharp.dll、UnityEngine.dll等。项目文件结构会变成MyFirstMod/ ├── About/ │ └── About.xml ├── Assemblies/ │ └── MyFirstMod.dll ├── Defs/ │ └── ... └── Source/ └── MyFirstMod/ ├── MyFirstMod.csproj └── Patch.csSource目录不是游戏加载必需的但你应该保留它方便后续维护。编译时把Assembly-CSharp.dll的引用路径指向 Rimworld 安装目录下的RimWorldWin64_Data/Managed/。注意不要把这些原版 DLL 复制到你的 Mod 里一起发布那会涉及版权问题而且游戏加载时可能冲突。一个最简单的 Harmony 补丁示例修改Pawn的移动速度using HarmonyLib; using Verse; namespace MyFirstMod { [StaticConstructorOnStartup] public static class HarmonyInit { static HarmonyInit() { var harmony new Harmony(yourname.myfirstmod); harmony.PatchAll(); } } [HarmonyPatch(typeof(Pawn), nameof(Pawn.Tick))] public static class Pawn_Tick_Patch { static void Postfix(Pawn __instance) { if (__instance.IsColonist __instance.Map ! null) { // 每 tick 给殖民者加一点移动进度实际项目中应更精确 } } } }[StaticConstructorOnStartup]保证这个静态构造函数在游戏启动时执行harmony.PatchAll()会扫描当前程序集里所有带[HarmonyPatch]的类并应用。Postfix表示在原方法执行后插入逻辑。__instance是 Harmony 的命名约定代表被 Patch 的实例本身。注意Harmony 的PatchAll()只扫描调用它的那个程序集。如果你有多个 DLL每个都需要自己的初始化入口或者在一个主 DLL 里手动Patch其他程序集的方法。3. 从项目源码到可加载 Mod编译、打包、进游戏验证3.1 用 dotnet 命令行编译 Rimworld Mod 的完整命令Rimworld 的 Mod 项目通常是 .NET Framework 4.7.2 或 4.8 的类库。用 Visual Studio 当然可以但如果你只想快速验证dotnetCLI 更直接。前提是你已经装了 .NET SDK并且知道 Rimworld 的安装路径。假设 Rimworld 装在D:\SteamLibrary\steamapps\common\RimWorld项目在D:\Mods\MyFirstMod\Source\MyFirstModcsproj文件内容如下Project SdkMicrosoft.NET.Sdk PropertyGroup TargetFrameworknet472/TargetFramework AssemblyNameMyFirstMod/AssemblyName RootNamespaceMyFirstMod/RootNamespace LangVersionlatest/LangVersion /PropertyGroup ItemGroup Reference IncludeAssembly-CSharp HintPathD:\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll/HintPath Privatefalse/Private /Reference Reference Include0Harmony HintPathD:\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\0Harmony.dll/HintPath Privatefalse/Private /Reference Reference IncludeUnityEngine.CoreModule HintPathD:\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll/HintPath Privatefalse/Private /Reference /ItemGroup /ProjectPrivatefalse/Private很重要。它告诉编译器不要把这些 DLL 复制到输出目录。如果你忘了写编译出来的Assemblies文件夹里会多出一堆原版 DLL游戏加载时可能因为版本不一致直接崩溃。编译命令cd D:\Mods\MyFirstMod\Source\MyFirstMod dotnet build -c Release -o ..\..\Assemblies-c Release用发布配置-o指定输出目录直接指向 Mod 的Assemblies文件夹。编译成功后MyFirstMod.dll会出现在Assemblies下。如果你在编译时看到error CS0246: 找不到类型或命名空间名九成是HintPath写错了或者 Rimworld 版本更新后 DLL 名字变了。去Managed目录下dir一下确认文件名。3.2 打包成 Steam 创意工坊可识别的目录格式Rimworld 的 Mod 加载不依赖压缩包它直接读文件夹。所以「打包」其实就是确保目录结构正确然后整个文件夹丢进Mods目录。标准发布结构MyFirstMod/ ├── About/ │ ├── About.xml │ └── Preview.png 可选创意工坊缩略图 ├── Assemblies/ │ └── MyFirstMod.dll ├── Defs/ │ └── ThingDefs/ │ └── MyItems.xml ├── Languages/ │ └── ChineseSimplified/ │ └── DefInjected/ │ └── ThingDef/ │ └── MyItems.xml └── Textures/ └── Things/ └── Item/ └── Resource/ └── AdvancedComponent.pngLanguages目录用于本地化。如果你在ThingDef里直接写了中文label游戏里能显示但其他语言的玩家看到的也是中文。正规做法是在Defs里用英文 key然后在Languages/ChineseSimplified/DefInjected/ThingDef/MyItems.xml里写翻译?xml version1.0 encodingutf-8? LanguageData MyMod_AdvancedComponent.label高级零部件/MyMod_AdvancedComponent.label MyMod_AdvancedComponent.description用于高级制造的高级零部件。/MyMod_AdvancedComponent.description /LanguageData这样游戏会根据当前语言自动切换。如果你只做中文 Mod直接写在Defs里也能跑但后续想加英文支持就得回头改。Preview.png是创意工坊上传时用的缩略图尺寸建议 512x512放在About目录下。Steam 上传工具会自动读取。3.3 进游戏后 Mod 不显示或报错时看哪个日志Rimworld 的日志文件在%USERPROFILE%\AppData\LocalLow\Ludeon Studios\RimWorld by Ludeon Studios\Player.log。每次启动游戏都会覆盖这个文件。如果你在 Mod 列表里看不到自己的 Mod或者加载时红字报错第一时间打开这个日志搜索你的packageId或 Mod 文件夹名。常见错误对照日志关键词原因解决Invalid packageIdAbout.xml里packageId格式不对改成全小写、无空格、带点号Could not load file or assemblyDLL 引用了不存在的依赖检查Assemblies下是否缺 DLL或HintPath是否失效Duplicate defName你的 Def 和原版或其他 Mod 重名加前缀或改用 PatchXML errorXML 语法错误比如标签未闭合用浏览器打开 XML 验证格式Harmony patch failed目标方法签名变了确认游戏版本和Assembly-CSharp.dll版本一致日志里报错的行号是 XML 文件的行号不是 C# 的。如果你在Defs里写了注释!-- --行号会算上注释行别被误导。提示开发阶段建议在游戏设置里打开「开发者模式」然后在游戏内按~打开控制台输入log可以实时看日志不用切出去。4. Rimworld Mod 制作避坑从血泪经验里挑出的 5 个翻车点4.1 现象Mod 加载后游戏卡在加载界面日志无报错原因About.xml里supportedVersions写了多个版本但游戏当前版本不在列表里或者packageId和文件夹名冲突。Rimworld 在加载时会尝试解析所有 Mod 的元数据如果某个 Mod 的About.xml格式正确但版本不匹配它不会报错而是静默跳过但可能因为依赖关系导致加载流程卡住。解决只写你实际测试过的版本号。如果你不确定先只写当前版本比如li1.5/li。另外Mod 文件夹名和packageId不需要一致但建议保持一致方便排查。4.2 现象XML 里改了数值进游戏没生效原因你新建了一个ThingDef但defName和原版重复游戏加载时用了原版的你的被覆盖了。或者你用了Patch但xpath写错了补丁没匹配到目标节点。解决先确认你的defName是唯一的。如果是修改原版用Patch而不是重新定义。xpath可以用在线工具验证或者先在游戏里用开发者模式的「Def 查看器」找到目标 Def 的完整路径。4.3 现象Harmony 补丁编译通过但运行时没执行原因[StaticConstructorOnStartup]的类没有被任何地方引用或者PatchAll()调用的程序集不对。Rimworld 只会加载Assemblies下的 DLL但不会自动执行里面的静态构造函数除非你用了[StaticConstructorOnStartup]并且这个类在加载的程序集里。解决确认HarmonyInit类在MyFirstMod.dll里并且PatchAll()没有传参数默认扫描当前程序集。如果你有多个 DLL每个都需要自己的HarmonyInit。4.4 现象创意工坊上传后订阅者说 Mod 不工作原因你上传时只传了About和Defs忘了Assemblies或Textures。Steam 创意工坊上传工具默认只包含你选中的文件夹如果你在About里写了Preview.png但没上传订阅者看到的缩略图是空白的。解决上传前在本地把整个 Mod 文件夹复制到 Rimworld 的Mods目录启动游戏确认能加载、能生效。然后再用上传工具确保所有子目录都被勾选。4.5 现象游戏更新后之前能用的 Mod 报红字原因Rimworld 大版本更新会改Assembly-CSharp.dll里的方法签名你的 Harmony 补丁目标方法可能被重命名或参数变了。XML Def 的结构也可能调整比如某个字段从必填变成可选或者反过来。解决每次游戏更新后重新编译你的 DLL并检查About.xml里的supportedVersions。如果目标方法签名变了去Assembly-CSharp.dll里用反编译工具比如 dnSpy找新签名更新[HarmonyPatch]特性。5. 用项目源码做进阶Patch 原版 Def 与多 Mod 兼容的写法5.1 用 xpath 补丁修改原版物品的堆叠上限直接重新定义ThingDef会覆盖原版导致其他 Mod 的修改失效。正确做法是用Patch?xml version1.0 encodingutf-8? Patch Operation ClassPatchOperationReplace xpath/Defs/ThingDef[defNameComponent]/stackLimit/xpath value stackLimit500/stackLimit /value /Operation /PatchPatchOperationReplace会找到defNameComponent的ThingDef把stackLimit替换成 500。如果原版没有stackLimit字段这个操作会失败日志里报xpath没匹配到。更安全的写法是PatchOperationAdd或PatchOperationConditional。xpath的语法是标准 XPath 1.0。/Defs/ThingDef[defNameComponent]表示从根节点Defs下找所有ThingDef筛选defName等于Component的那个。注意defName是区分大小写的。5.2 多 Mod 兼容用 Mod 依赖和加载顺序控制如果你的 Mod 依赖另一个 Mod 的 Def需要在About.xml里声明modDependencies li packageIdauthor.othermod/packageId displayNameOther Mod/displayName /li /modDependencies loadAfter liauthor.othermod/li /loadAftermodDependencies告诉游戏如果订阅者没装author.othermod在 Mod 列表里给你的 Mod 标红提示缺少依赖。loadAfter控制加载顺序确保你的 Patch 在目标 Mod 之后执行。如果你要修改的 Def 可能被多个 Mod 修改用PatchOperationFindMod做条件判断Operation ClassPatchOperationFindMod mods liauthor.othermod/li /mods match ClassPatchOperationReplace xpath/Defs/ThingDef[defNameMyMod_Item]/stackLimit/xpath value stackLimit1000/stackLimit /value /match nomatch ClassPatchOperationReplace xpath/Defs/ThingDef[defNameMyMod_Item]/stackLimit/xpath value stackLimit500/stackLimit /value /nomatch /Operation这样如果检测到author.othermod存在就用 1000否则用 500。PatchOperationFindMod是 Rimworld 1.1 之后加入的老版本没有。5.3 验证补丁是否生效开发者模式下的 Def 查看器进游戏后按~打开控制台输入defcomponent或者直接在开发者菜单里找「Def 查看器」。搜索你的defName看stackLimit字段的值是不是你改的。如果没变说明 Patch 没执行。另一个方法是看日志。PatchOperation执行成功不会写日志但失败会写Patch operation failed并附带xpath。如果你在About.xml里开了debugtrue/debug日志会更详细。我自己的习惯是每次改完 Patch先不启动游戏用xmllint验证 XML 格式然后进游戏用开发者模式确认。这样能省掉很多反复重启的时间。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑