rimworld吧 关注:247,152贴子:4,447,795

RimWorld:XML文件结构

只看楼主收藏回复

前言
相关内容来自RimWorld Wiki ,本文仅做翻译和有限的补充,除非另有说明,所属内容均在 CC BY-SA 3.0 下提供。
贴吧这暂时不能放原文链接了,之前还只是删楼,上次直接给我号封了。CSDN那边仍然正常展示原文链接。
CSDN链接:http://t.csdnimg.cn/zUnj6
以及赛博乞讨:
https://i0.hdslb.com/bfs/new_dyn/54bf946e49f7612dcc13ca07cf587f098040337.png
水平有限,如有错漏,敬请见谅。
说实话,这篇翻译的我自己也是云里雾里的,为了方便理解还做了一些补充,但总体观感还是不太好,
关于本篇
在本教程中,我们将开始学习XML语法,为什么游戏使用XML,以及XML都做了什么。(译者:感觉没讲很多)
你将学习def文件的默认结构:

以及如何使用Name, ParentName和Abstract进行继承。


IP属地:中国香港1楼2024-01-19 20:46回复
    Def的默认结构
    标准defs:
    可以在Core文件夹中找到Def.xml文件,例如:

    这个文件的第一行是:

    这行告诉我们这个.xml文件使用UTF-8编码并使用1.0版本的XML,这也是这些字段的默认值。部分XML编辑器会在不通知用户的情况下默认隐藏这行,并将其保存在文档顶部。
    第一行之后,文件结构由<Defs>和<Def>组成:

    每个<Def>都包含某个东西的定义(def),用来具体说明每一个可修改的元素和属性。例如:对一个特定的Thing有<ThingDef>。
    <Defs>的是所有<Def>的根标签,所有具体类型的<Def>(如ThingDef, RecipeDef, BiomeDef等等)都被包含在<Defs>中。


    IP属地:中国香港2楼2024-01-19 20:48
    回复
      2025-05-09 17:03:45
      广告
      完整结构:
      模组的Def.xml文件需要遵循下例的结构,如果一个.xml文件中存在多个<Defs>或者有<Def>处于<Defs>之外,模组将不能运行。

      语法和关键词
      你肯定?已经注意到,XML文件中的一些单词似乎被反复使用。注意单词Abstract, Name和Class。这些词被称为关键词,它们是了XML语言语法的一部分。一个词被当做关键词使用意味着它有一个预期目的,这个词也只能作为关键词使用。出于这个原因,你应该了解一些规则,因为违反这些规则是导致bug和错误的常见原因。
      当你使用关键词的时候,每次都应该完全一致的拼写。一个常见的错误是无意中使用了不同的大小写。例如,对于关键词Abstract来说,Abstract(√)和abstract(×)是不同的,单词拼写错误会引起一些问题。
      一般来说,在编辑或创建新的<Def>时应避免使用关键词作为属性。几乎可以肯定的是,这样做会导致问题,所以最好避免使用超出其预期用途的关键词。


      IP属地:中国香港3楼2024-01-19 20:49
      回复
        继承
        摘要: 在XML中,继承用于减少冗余。如果某个标签有ParentName="YourParentName"属性,它会获取具有Name="YourParentName"属性的标签的所有内容。如果这个父类标签不完整,将在加载时导致游戏崩溃,可以用Abstract="True"来阻止它被加载到游戏中。
        注意:在A15更新之后,抽象类型(Abstract)的标签已经可以直接从Core和其他模组继承。重新定义Core的抽象标签是导致模组兼容性问题的常见原因,因为在抽象标签被重新定义后加载的任何模组都将使用修改后的版本而不是Core的原始版本。因此,在为模组定义抽象标签时,建议尽量避免覆盖Core的抽象标签,而是使用不太可能被其他模组意外使用的唯一名称。
        Basegun ThingDef
        文件ThingDefs_Misc\Weapons\BaseWeapons.xml中首先是一个带有Name和Abstract 属性的<ThingDef>标签:

        Abstract="True"意味着这个<ThingDef>不会加载到游戏中,而是在读取和处理这个<ThingDef>中的内容后,继续读取XML文件,在留下任何可能复制(获取,继承)于该<ThingDef>的内容后丢弃这个<ThingDef>。这一系列操作都是通过这样一个标签完成的:

        这意味着<ThingDef Abstract="True" Name="BaseWeapon">的所有内容可以在游戏中反复使用,但BaseWeapon本身并不存在于游戏中 —— 这就是抽象。
        Name属性表示这个<ThingDef>的内容可以被另一个<ThingDef>继承(读取 | 复制)。因此,你可以将所有在整个文件中重复的内容写在一个位置,例如:

        上例表示该Thing属于物品(Item),而不是建筑(Building)或其他什么东西。因为在各种内容中都有大量重复的标签,这么做可以极大地压缩XML文件。
        完整的BaseWeapon只需要在文件中定义一次,然后可以通过以下方式继承(复制):

        <ThingDef ParentName="Parent">将继承<ThingDef Name="Parent">的所有内容。
        另一个常见父类标签是BaseBullet,它包含各种普通子弹Def中的常见的重复元素,比如子弹不使用生命值(hitpoints):

        文件ThingDefs_Misc\Weapons\BaseWeapons.xml中的下一个Def是:

        它继承了BaseWeapon的内容,并被所有带有ParentName="BaseGun"的ThingDefs继承。
        把每个<ThingDef Name ="...">看作一种模板可能会有所帮助:
        - BaseWeapon包含了适用于所有武器的基本信息:它们可以被拖拽、装备、选择;
        - BaseGun包含了所有枪械的基本信息:它们是WeaponsRanged类的一部分,可以被冶炼,可以有艺术;
        - BaseMakeableGun依次包含可制作的枪械的信息。


        IP属地:中国香港4楼2024-01-19 20:53
        回复
          可以多讲点XPath和继承的么


          IP属地:新加坡来自Android客户端5楼2024-01-19 20:54
          收起回复
            下表的内容是继承在Rimworld的XML中的工作方式,它可能会对你有所帮助,记得在阅读下面的内容后整理一下思绪:
            1. 游戏启动;
            2. 游戏开始单独的加载每个模组;
            ①. 从每个标签中取得继承信息;
            ②. 任何具有ParentName属性的标签都将继承(读取 | 复制)并应用具有与其关联的Name属性的标签的所有内容。
            ⑴. 子类标签得到内容;
            ⑵. 父类标签提供内容;
            ⑶. 一个标签可能同时是子类标签和父类标签;
            ⑷. Path操作在继承发生之前就完成了,也就是说此时子类继承的是被Path过的父类。
            ③. 内容信息(读取:在<ThingDef>之间的所有内容)被获取并应用于每个标签;
            ⑴. 来自父类标签的内容此时被覆盖;
            ④. 所有的<Def>都获取了完整的内容之后,抽象(Abstract)类的 def 就会被丢弃,从而被游戏忽略;
            ⑤. 所有的<Def>及其内容完成加载。
            3. 模组加载完成。


            IP属地:中国香港6楼2024-01-19 20:56
            回复
              图解(译者附)
              这段翻译的太诡异了,想来想去还是附个图解把。
              假设我们在XML中定义了三个<ThingDef>:



              加载过程:
              1. 执行Path操作。如果BaseWeapon是Path的目标,那么BaseWeapon将在此时被修改,之后使用的BaseWeapon都是被修改(Path)过的;
              2. 加载Thing A,在加载Thing A时在会发现ParentName="BaseWeapon";
              3. 首先继承BaseWeapon的内容,此时Thing A是这样的(注意这是Thing A):

              4. 在继承完BaseWeapon的内容后,再加载Thing A自己的内容:

              5. 如果Thing A自己的内容与BaseWeapon的内容有重叠,以Thing A自己的内容优先,来自BaseWeapon的内容会被覆盖;
              6. 加载Thing B的时候也一样:

              7. 继续加载,直到所有继承了BaseWeapon的Thing全都加载完;
              8. 再之后BaseWeapon就没用了,因为它有Abstract="True"属性,游戏会直接丢弃它,不会真正加载:


              IP属地:中国香港7楼2024-01-19 21:01
              回复
                代码解释(有修改)
                你在XML文件中编写的内容:

                游戏最终得到的内容:



                IP属地:中国香港8楼2024-01-19 21:03
                回复
                  2025-05-09 16:57:45
                  广告
                  完整代码
                  添加继承之后,我们的XML文件结构看起来像这样:

                  - <Defs>是根节点,这是强制要求;
                  - <Def>必须有一个特定的名称,与C#中的类型相匹配,如<ThingDef>。


                  IP属地:中国香港9楼2024-01-19 21:04
                  回复
                    停止继承
                    在某些情况下,你不希望子类标签使用父类标签中一些的值。你可以通过在子类标签中指定inherit ="False"来告诉子标签不要继承父类标签的部分内容,以狙击步枪为例:
                    上例将只使用SniperRifle作为<weaponTags>,而不继承父类<weaponTags>标签。这对列表元素特别有用,因为列表元素的继承方式是添加。
                    这样做的好处是,可以在保持父类标签不变的情况下让子类选择要继承的元素和属性。


                    IP属地:中国香港10楼2024-01-19 21:05
                    回复
                      普通元素与列表元素继承的不同(译者附)
                      上面提到了当子类标签具有和父类标签重叠的内容时,以子类标签自己的内容优先,来自父类标签的内容会被覆盖。
                      如:

                      因此,如果要改写父类标签中的普通元素,只需在子类中重新赋值该元素即可。但如果是列表元素,情况会有所不同。子类标签不会覆盖掉父类标签的列表内容,仅仅会将自己的内容添加到列表中。
                      如:

                      因为,如果要改写父类标签中已经赋值的列表元素,必须停止该列表元素的继承(使用inherit ="False"属性),并在子类中完全重新赋值。
                      如:

                      备注:在<li>标签上添加inherit ="False"属性没有意义。


                      IP属地:中国香港11楼2024-01-19 21:07
                      收起回复
                        最后的小示例:

                        截图不完全的内容:<!-- <li Class = "CompOne">虽然存在于父标签的comps中,但我们并没有继承父标签的comps,因此必须重新编写 -->


                        IP属地:中国香港12楼2024-01-19 21:08
                        回复
                          好好好


                          IP属地:广东来自Android客户端13楼2024-01-19 22:06
                          回复
                            这游戏门槛好高


                            IP属地:北京来自Android客户端14楼2024-01-19 22:31
                            回复
                              2025-05-09 16:51:45
                              广告
                              给大佬递精神茶


                              IP属地:广东来自Android客户端15楼2024-01-20 13:09
                              回复