rimworld吧 关注:258,571贴子:4,723,784

Rimworld Mod xml教程 这可能是你见过的最细的MOD教程了

只看楼主收藏回复


基础篇 第一讲
你好!我是旋风。既然你看到了这个教程,想必你有成为一个mod制作者的兴趣。
我们常常把各类教程的作者比作一个引路人。在这里,我将教会你如何去制作一个简单的mod——而更重要的是,我希望能引导你走上探索制作方法的道路。
我私下带过不少新人,常见的问题有两点。一是在获得这“金手指”后,只是为了满足一时的快感去“魔改”,在mod中无脑地刷数据甚至堆0,导致劣质mod的泛滥。二是仅凭着一时的热血去制作mod,在遇到困难或者制作周期过长时便轻易地选择了放弃。
其实,我认为做mod的主要动力还是“自嗨”,毕竟只有让自己感到快乐的作品才能带给别人快乐;另一方面,一个作品就像自己的孩子,我们需要为其负责,并不断努力把他们打造成更优秀的作品。
从现在开始,除了一颗希望mod越来越好的心以外,什么要求都没有。
愿你获得启示。


IP属地:福建1楼2025-05-12 14:02回复
    基础篇 第二讲:MOD整体结构
    本课将讲述mod的组成部分及每个部分对应的编辑工具
    内容:
    About:管理mod的外在设置,内含:
    About.xml:编辑mod的名字,Id,作者,介绍,以及与其他mod的排序、需求、兼容性提示等设定。
    Preview.png:mod封面,用于游戏内与工坊处。
    Defs:mod新增内容的数据库。
    Assemblies:mod新增内容的程序集。
    Textures:存放mod新增的贴图。
    Sounds:存放mod新增的音频。
    Languages:存放语言包。
    工具:
    XML方面这里推荐三个工具
    Notepad++
    >文本式编辑器
    >良好的查找器和替换器
    >缺少实时错误检测
    >可以自动补全同一个文件内已经出现过的一串文本
    >无格式修正
    >简单朴素
    XML Notepad
    >表格式编辑器
    >没有文件内查找功能
    >自动编译,几乎无法出错
    >自动完成格式编辑
    >极易上手
    Visual Studio
    >文本式编辑器
    >优秀的查找器和替换器
    >可以同时管理一整套文件
    >实时检查错误
    >格式修正
    >能够编译各种语言
    >高级mod必备
    程序:反编译工具+代码编辑器
    (1).反编译工具
    制作mod程序集时会不可避免地需要研究游戏本身的程序,虽然可以去下载源代码
    但我个人更喜欢直接用反编译工具来辅助研究。
    dnSpy
    >UI与Visual Studio的风格一致
    >样式丰富
    >反编译“本地方法”、lambda表达式时会乱码
    >跳转代码方便快捷
    >喜欢把字段放在文件末尾
    >不再更新
    ILspy
    >UI别致
    >样式较少
    >反编译消耗时间长
    >能正常编译大部分代码
    >持续维护
    .代码编辑器
    每个程序员都有自己常用的编辑器,此处没有要求,能编译C#程序即可。教程中出现的,也是最常见的,为Visual Studio
    在早期制作mod时,无需下载程序相关软件;即使不制作程序集,你也能制作出包括武器,家具,衣服甚至派系的好mod,这是因为Rimworld本身的框架已经足够丰富。而只有当你不满足现状,且自身具备足够的面向对象编程经验与C#语言基础时,才有必要获取以上工具进行程序制作。
    本教程会适当使用反编译器来展示游戏框架的内容,同时我会附上代码讲解以方便没有任何编程基础的人也可以正常使用我的教程。


    IP属地:福建2楼2025-05-12 14:03
    回复
      2025-08-07 20:26:26
      广告
      不感兴趣
      开通SVIP免广告
      基础篇 第三讲:第一个MOD
      我相信各位一定急于做出自己的第一个mod,因此,我决定在开启我们的正式教学之前,让大家过一过瘾。
      我为大家准备了一份礼物,就放在我们的网盘里
      在下方百度网盘中找到“我们的第一份mod”下载并解压,我们能找到以下文件:
      >一套无内容的文件夹框架
      >一张枪械贴图FirstGun.png
      >一张封面贴图Preview.png
      >一个mod管理文件About.xml
      >一个枪械数据文件Weapon.xml
      来吧,让我们试试!
      首先,制作mod时请记得关闭其他mod,避免造成冲突影响mod制作【尤其是CE】
      其次,每次mod文件被修改,都需要将Rimworld进程完全关闭后再启动。
      配置mod属性
      将About.xml拖入mod中的Abouts文件夹
      使用xml编辑软件打开该文件,你可以看到我需要你修改的地方,例如第三行的
      <name>【为你的mod命名】</name>
      把这里的括号及其内部的内容替换为你想要写的东西:
      <name>我们的第一个mod</name>
      该文件内的其他东西请不要乱动,我们会在后方的章节内详细讲述其作用
      下一步,将Preview.png拖入Abouts文件夹
      现在,我们已经得到了一个没有任何内容,但能够被游戏识别的mod,你可以启动游戏来在mod列表中找到它。
      添加新内容
      将FirstGun.png拖入Texutures文件夹
      将Weapon.xml拖入Defs文件夹
      使用XML编辑器打开Weapon.xml,与刚才相同地,将我们给出的东西替换为你想要的内容,其他东西就不做修改。
      修改结束后,别忘了保存文件。
      完事后,你就可以在游戏中看到它了,赶紧体验一下吧!
      若你的游戏内容没有变化,请检查是否保存了文件,是否重启了游戏。


      IP属地:福建3楼2025-05-12 14:04
      收起回复
        我喜欢把XML形象地称为“数据库”,因为它为游戏提供了大量数据。一个数据包含其名字(参数名)和内容(参数)。每个参数名都在程序中被声明和应用,用简单易懂的话来说,就是我们必须按照程序给出的数据来制作。如果使用了一个程序中不存在的参数名,便会在进入游戏时报错,这点我们会在后期归纳报错时详细讲解。而数据的内容则按照一定的类型去完成,不符合类型地去填写内容往往会报错。若一个数据被程序提及,却没有被数据库提及,则使用程序给出的默认值。
        【注:这里的参数名其实被称为“标记”,每一个键值对被称为一个元素,但为了方便新手理解,我不引入相关的专业名词】
        每一个XML文件的第一行必定为
        <?xml version="1.0" encoding="utf-8"?>
        是XML文件的识别码。
        ①文本式编辑
        基本格式为:
        <参数名>参数</参数名>
        这里就像一个前后括号包着一个东西,所以需要十分注意“后括号”的"/"字符。我们称这种参数是一个简单的值的类型为“基础类型”。部分数据的参数不是简单的一个值,而可能由其他数据组成,形成“复合式”甚至“嵌套式”的结构,这是因为它们的类型为“复合类型”。
        <大参数名>
        <子参数A>A</子参数A>
        <子参数B>B</子参数B>
        </大参数名>
        <大参数名>
        <子参数C>C</子参数C>
        <子参数D>
        <孙参数>孙</孙参数>
        </子参数D>
        </大参数名>
        有极少数情况,我们不需要参数:
        <参数名></参数名>
        此时可以简写为:
        <参数名/>
        有时,在参数名处可以加上一些游戏预设的记号,此时请把记号置于前面的参数名处,格式为 记号名="记号内容" ,例:
        <参数名A Inherit="False">a</参数名A>
        【注:“记号”在XML中学术译名为属性】
        ②.注释
        注释写法为<!--注释内容-->,可以换行:
        <!--
        啊对对对
        -->
        不允许嵌套,如这么做是要报错的:
        <!--
        <!--啊错错错-->
        -->
        ③List结构
        在复合结构中,有一种特殊的数据类型(以后我会以“List类型”来形容它)。正常的复合结构,一个大数据所包括的小数据,每一个数据仅对应一个值。给一个数据对应多个值,或一个大数据内出现多次同一个数据是不被允许的,而List则能够解决这一问题。此处给出一个“人际关系”的例子,其中基础类型的参数,类型均为字符串,希望填写一个称呼,
        <人际关系>
        <妻子>夫人</妻子>
        <孩子>大儿子,二儿子</孩子>
        </人际关系>
        显然是错误的,程序会认为有一个孩子被称为“大儿子,二儿子”
        ==========================
        <人际关系>
        <妻子>夫人</妻子>
        <孩子>大儿子</孩子>
        <孩子>二儿子</孩子>
        </人际关系>
        “孩子”出现了两次,会导致程序报错
        =========================
        可能可以用这种方式解决:
        <人际关系>
        <孩子A>大儿子</孩子A>
        <孩子B>二儿子</孩子B>
        </人际关系>
        问题就在于,每多一个孩子,程序就要多规定一个新数据
        =========================
        List类似一堆同类型数据的有序集合体,能够让“一个”数据有“多个内容”。于是,若把“孩子”的类型设为“List类型”后:
        <人际关系>
        <妻子>夫人</妻子>
        <孩子>
        <li>大儿子</li>
        <li>二儿子</li>
        </孩子>
        </人际关系>
        此处的“孩子”显然成为了一个复合结构。其中每一个“li”数据被称为一个“元素”。事实上,这种元素可以被不断添加进list当中。
        List结构是允许嵌套的,下面是一段疯狂的代码:
        <list>
        <li>
        <li>文</li>
        <li>化</li>
        <li>有</li>
        <li>限</li>
        </li>
        <li>
        <li>公</li>
        <li>司</li>
        </li>
        </list>
        在mod制作中,数据类型由程序决定,xml作为一个数据库是没有办法修改的。制作者们不能自行将一个数据变为List类型,也不能以简单类型的方式来写一个List。在日后的学习过程中,我会给出它们的类型,需要仔细辨认。
        <list><li>A</li></list>
        单元素的list通常这么写,也可以换行
        ④父对象关系:ParentName,Name,Inherit记号
        数据库里有这堆东西:
        <人们>
        <人>
        <称呼>父亲</称呼>
        <年龄>47</年龄>
        <单位>文化有限</单位>
        <地址>蒸汽社区</地址>
        <姓>郑</姓>
        </人>
        <人>
        <称呼>儿子</称呼>
        <年龄>23</年龄>
        <地址>蒸汽社区</地址>
        <姓>郑</姓>
        </人>
        </人们>
        我们会发现儿子与父亲有许多相同点:地址和姓。而如果父子间的相同点越来越多,或出现了二儿子,三儿子等,一些相同的数据就会重复的出现。而我们想修改这个“家族”的姓时又要全翻一遍来修改。事实上,儿子的部分数据应当永远与父亲相同。
        我们使用“父对象”来实现这种“继承”的功能:
        <人们>
        <人 Name=”爹”>
        <称呼>父亲</称呼>
        <年龄>47</年龄>
        <单位>文化有限</单位>
        <地址>蒸汽社区</地址>
        <姓>郑</姓>
        </人>
        <人 ParentName=”爹”>
        <称呼>儿子</称呼>
        <年龄>23</年龄>
        <单位 Inherit=”False”/>
        </人>
        </人们>
        前面提到过,一个未被数据库提及的数据将被视为默认值。在此处,由于“儿子”未提及“地址”与“姓”,且其继承了“爹”的数据,所以“地址”和“姓”就会直接被视为是“父亲”的“地址”和“姓”,而儿子自己本身具有的“称呼”和“年龄”,这两个数据将直接覆盖其父对象的对应数据;特别的,此处的“单位”数据没有对应的参数,而是使用了“Inherit=false”标签,表示该数据不继承父对象。
        从上不难得出使用方法:
        Name=”A”,ParentName=”A”
        其中,整个数据库仅允许出现一个被命名为A的Name,其所标记的数据体就是一个父对象;而所有被标记为ParentName=”A”的数据体都将以被Name=”A”标记的为父对象。显然,一个数据体不允许将自己视为自己的父对象,但继承关系是允许被逐级嵌套的:
        <人们>
        <人 Name=”一代目”>
        <称呼>爷</称呼>
        <姓>郑</姓>
        <地址>天地</地址>
        </人>
        <人 ParentName=”一代目”,Name=”二代目”>
        <称呼>爹</称呼>
        <地址>蒸汽社区</地址>
        </人>
        <人 ParentName=”二代目”>
        <称呼>崽种</称呼>
        </人>
        </人们>
        输出第三代人的信息,姓氏会直接继承“一代目”的姓,而地址则继承更近的“二代目”,大家可以自行分析。
        特别地,当某个数据体中存在复合数据时,将会全部拆到基础类型,而不会把复合数据视为整体:
        <信息表>
        <信息卡 Name=”卡”>
        <代号>A</代号>
        <内容>
        <工资>14000</工资>
        <年终>2000</年终>
        <五险一金>1000</五险一金>
        </内容>
        </信息卡>
        <信息卡 ParentName=”卡”>
        <代号>B</代号>
        <内容>
        <工资>9000</工资>
        </内容>
        </信息卡>
        </信息表>
        这里的“内容”作为一个复合数据,将会被拆分为多个数据来分别继承(如果拆出来的也有复合那么继续拆直到全为基础),所以B实际上的内容为{工资:9000,年终:2000,五险一金:1000},如果希望B的内容仅为{工资:9000},那么应当对“内容”使用Inherit记号。这样一来,其余两项就会因没有被数据库提及而使用默认值。
        List类型由于其特殊的有序性,在继承时会按序合并父对象与子对象的数据内容。


        IP属地:福建4楼2025-05-12 14:07
        收起回复
          收藏了


          IP属地:重庆来自Android客户端5楼2025-05-12 14:21
          回复


            IP属地:四川来自Android客户端6楼2025-05-12 14:32
            回复
              收藏了


              IP属地:四川来自Android客户端7楼2025-05-12 14:33
              回复


                IP属地:安徽来自Android客户端8楼2025-05-12 14:34
                回复
                  2025-08-07 20:20:26
                  广告
                  不感兴趣
                  开通SVIP免广告
                  先mark住


                  IP属地:日本来自Android客户端9楼2025-05-12 14:36
                  回复
                    好好好,大佬就是大佬


                    IP属地:江苏来自Android客户端10楼2025-05-12 14:37
                    回复
                      顶顶


                      IP属地:江苏来自Android客户端11楼2025-05-12 14:40
                      回复
                        收藏了


                        IP属地:安徽来自Android客户端12楼2025-05-12 14:43
                        回复
                          环世界青年大学习


                          IP属地:福建来自Android客户端13楼2025-05-12 14:45
                          回复
                            大佬,我们敬爱你呀!


                            IP属地:北京来自iPhone客户端14楼2025-05-12 14:48
                            回复
                              2025-08-07 20:14:26
                              广告
                              不感兴趣
                              开通SVIP免广告
                              学习学习


                              IP属地:山东来自Android客户端15楼2025-05-12 14:49
                              回复