Skip to content

新增元素

新增元素比新增物品更靠近游戏底层。它不仅要有 C# 代码,还要在 elements/custom_elements.yaml 里写物性数据。游戏先从 yaml 读取元素,再由代码给它补贴图、材质、动画和可生成的矿物实体。

这一章用 AuroraCrystal 作为示例,做一个可掉落、可储存的固体元素。

文件结构

text
MyElementMod/
├── elements/
│   └── custom_elements.yaml
├── assets/
│   └── textures/
│       └── AuroraCrystal.png
├── AuroraCrystalConfig.cs
├── AuroraCrystalSubstancePatch.cs
├── ModElements.cs
└── STRINGS.cs

custom_elements.yaml 是关键文件。没有它,ElementLoader 找不到新元素,后面的 C# 都接不上。

定义元素 ID

先把 ID 和 SimHashes 放在一个地方:

csharp
namespace MyElementMod
{
    public static class ModElements
    {
        public const string AuroraCrystalId = "AuroraCrystal";
        public static readonly SimHashes AuroraCrystal =
            (SimHashes)Hash.SDBMLower(AuroraCrystalId);
    }
}

Hash.SDBMLower() 要和 yaml 里的 elementId 对上。ID 改名时,这两个地方一起改。

写 custom_elements.yaml

yaml
---
elements:
  - elementId: AuroraCrystal
    specificHeatCapacity: 0.5
    thermalConductivity: 1.2
    solidSurfaceAreaMultiplier: 1
    liquidSurfaceAreaMultiplier: 1
    gasSurfaceAreaMultiplier: 1
    strength: 0.8
    highTemp: 1200
    highTempTransitionTarget: Magma
    defaultTemperature: 290
    defaultMass: 200
    maxMass: 500
    hardness: 20
    molarMass: 50
    lightAbsorptionFactor: 1
    radiationAbsorptionFactor: 0.5
    radiationPer1000Mass: 0
    materialCategory: BuildableRaw
    tags:
    - BuildableRaw
    buildMenuSort: 2
    isDisabled: false
    state: Solid
    localizationID: STRINGS.ELEMENTS.AURORACRYSTAL.NAME
    dlcId: ""

先做固体最省心。气体和液体还会牵涉管道颜色、状态转换、相变产物,建议等固体能稳定生成后再扩展。

注册矿物实体

元素本身只是物性,还需要一个可掉落、可储存的实体。固体矿物可以继承 IOreConfig

csharp
using UnityEngine;

namespace MyElementMod
{
    public sealed class AuroraCrystalConfig : IOreConfig
    {
        public SimHashes ElementID => ModElements.AuroraCrystal;

        public GameObject CreatePrefab()
        {
            return EntityTemplates.CreateSolidOreEntity(ElementID, null);
        }
    }
}

当前源码里的 IOreConfig 只需要 ElementIDCreatePrefab()。这样游戏就能把 AuroraCrystal 当作一种固体矿物来处理。

补材质和动画

yaml 负责物性,材质通常在 Assets.SubstanceListHookup 后处理。最稳的做法是复制一个原版物质的材质,再替换贴图和颜色:

csharp
using HarmonyLib;
using UnityEngine;

namespace MyElementMod
{
    [HarmonyPatch(typeof(Assets), "SubstanceListHookup")]
    public static class AuroraCrystalSubstancePatch
    {
        public static void Postfix()
        {
            Element element = ElementLoader.FindElementByHash(ModElements.AuroraCrystal);
            if (element == null || element.substance == null)
            {
                Debug.LogError("AuroraCrystal was not loaded from custom_elements.yaml");
                return;
            }

            Substance source = Assets.instance.substanceTable.GetSubstance(SimHashes.Granite);
            Material material = new Material(source.material)
            {
                name = "matAuroraCrystal"
            };

            Color32 color = new Color32(102, 220, 255, 255);

            element.substance.material = material;
            element.substance.colour = color;
            element.substance.uiColour = color;
            element.substance.conduitColour = color;
            element.substance.anim = source.anim;
        }
    }
}

如果需要自定义贴图,可以读取 assets/textures/AuroraCrystal.png,再赋给 material.mainTexture。先复用花岗岩动画,能少踩很多显示问题。

本地化文本

csharp
namespace MyElementMod
{
    public static class STRINGS
    {
        public static class ELEMENTS
        {
            public static class AURORACRYSTAL
            {
                public static LocString NAME = "极光晶体";
                public static LocString DESC = "一个用于演示新元素注册流程的自定义固体元素。";
            }
        }
    }
}

localizationID 对应 STRINGS.ELEMENTS.AURORACRYSTAL.NAME,路径不一致时元素名会显示异常。

常见问题

日志里提示元素没加载,先检查 elements/custom_elements.yaml 有没有打包到 Mod 输出目录。

游戏能启动但元素无贴图,先复用原版 Graniteanimmaterial,确认流程通了再换自己的资源。

元素不能作为建筑材料,检查 materialCategorytags。常用的是 BuildableRawMetalRefinedMetal,不要随便写一个游戏不认识的标签。