世界生成
新元素、新植物、新生物做出来以后,如果只能靠调试工具刷出来,玩家体验是不完整的。让它们自然出现在新地图里,需要接世界生成系统。
缺氧的世界生成分成三层:worlds → subworlds → features。每一层嵌套引用,最终落实到具体元素和实体。Mod 按需要放对应层级的 yaml 文件即可。
资源位置
原版的世界生成资源在游戏目录下:
OxygenNotIncluded_Data/StreamingAssets/
└── worldgen/
├── biomes/ # 生态群系(地层构成)
├── features/ # 矿脉、空洞、遗迹等局部地形
├── subworlds/ # 子世界(群系、温度带、特色地形的组合)
└── worlds/ # 完整世界(选出所有 subworld)Mod 里不需要完整复制,只放你要新增或修改的部分:
MyWorldgenMod/
└── worldgen/
├── features/
│ └── rift/
│ └── MyCrystalPocket.yaml # 自定义矿脉
├── subworlds/
│ └── rift/
│ └── CrystalRift.yaml # 引用上面的 feature
└── worlds/
└── MyCrystalWorld.yaml # 引用上面的 subworld三层结构
worlds/MyWorld.yaml
└─ 引用 subworlds/rift/CrystalRift.yaml
└─ 引用 features/rift/MyCrystalPocket.yaml
└─ 使用 element: AuroraCrystal(来自 elements/custom_elements.yaml)每一层都是独立文件。上层通过引用路径找到下层,游戏在生成世界时逐层解析。
第一层:Feature(矿脉 / 局部地形)
Feature 是最小的世界生成单元——一团矿物、一个空洞、一片遗迹。如果只是想让你新注册的元素以矿脉形式出现,从这里开始最合适。
worldgen/features/rift/MyCrystalPocket.yaml:
tags:
- AllowExceedNodeBorders
shape: Blob
borders:
- 1
- 2
blobSize:
min: 10
max: 18
ElementChoiceGroups:
RoomCenterElements:
selectionMethod: WeightedResample
choices:
- element: AuroraCrystal
weight: 1
overrides:
massOverride: 200
temperatureOverride: 290
RoomBorderChoices0:
selectionMethod: WeightedResample
choices:
- element: Granite
weight: 2
- element: AuroraCrystal
weight: 1
overrides:
massOverride: 200
temperatureOverride: 290关键字段:
element: AuroraCrystal— 必须和custom_elements.yaml里的elementId完全一致。massOverride— 每格元素质量(kg)。固体一般100~500。temperatureOverride— 开尔文温度。290约等于 17°C。shape: Blob— 不规则团块。其他选项包括Circle(圆形)、Line(线状)等。blobSize— 团块占据的格子数范围。selectionMethod: WeightedResample— 按权重随机选。weight越大越容易出现。
第二层:Subworld(子世界)
Feature 不会自己生成。必须被某个 subworld 引用。
worldgen/subworlds/rift/CrystalRift.yaml:
biomeNoise: noise/Sandstone
temperatureRange: Room
density:
min: 8
max: 12
sampleBehaviour: PoissonDisk
biomes:
- name: biomes/Sedimentary/Basic
weight: 1
features:
- type: features/rift/MyCrystalPocket
zoneType: Sandstone关键字段:
features— 引用的 feature 路径列表。features/rift/MyCrystalPocket对应worldgen/features/rift/MyCrystalPocket.yaml。biomes— 这个 subworld 使用哪些群系。biomes/Sedimentary/Basic对应worldgen/biomes/Sedimentary/Basic.yaml(砂岩生态)。temperatureRange— 温度范围。Room是常温(约 20°C),还有Cold、Hot、VeryCold等。density— 子世界内部密度(影响 feature 和其他内容排布)。sampleBehaviour: PoissonDisk— 采样方式,决定内容物怎么分布。
第三层:World(完整世界)
World 把所有 subworld 组合起来,定义它们在整张地图上的分布。
worldgen/worlds/MyCrystalWorld.yaml:
subworldFiles:
- name: subworlds/sandstone/SandstoneStart
- name: subworlds/rift/CrystalRift
minCount: 4
- name: subworlds/magma/Bottom
unknownCellsAllowedSubworlds:
- tagcommand: Default
command: Replace
subworldNames:
- subworlds/rift/CrystalRift
- subworlds/sandstone/Sandstone关键字段:
subworldFiles— 这个世界会出现的所有 subworld 列表。minCount控制最少出现次数。unknownCellsAllowedSubworlds— 地图上未分配区域填充时,用哪些 subworld 来补。
如果只写了 feature 和 subworld,但 World 没有引用它,地图里仍然不会出现新内容。
直接混进 Biome 地层
如果想让新元素像砂岩、铜矿那样成为普通地层,可以修改 biome 文件:
worldgen/biomes/Sedimentary/Basic.yaml(需要修改原文件或在 Mod 里覆盖):
TerrainBiomeLookupTable:
add:
Basic:
- content: SandStone
bandSize: 0.2
- content: Algae
bandSize: 0.4
- content: AuroraCrystal
bandSize: 0.05
overrides:
massOverride: 200
temperatureOverride: 290
- content: Oxygen
bandSize: 1.3bandSize 是地层厚度占比。0.02 ~ 0.08 适合稀有矿物,太大了会像主岩层一样铺满。
POI 模板
模板(Points of Interest)是固定布局的预制房间,比如遗迹、初始基地、固定矿点:
- element: AuroraCrystal
mass: 200
temperature: 290模板里直接写元素和格子位置,不依赖 feature / subworld 链。适合做遗迹、固定生成点,缺点是不随机分布。
调试世界生成
世界生成最难调试——它只在生成新世界时运行,旧存档不会凭空刷新。
生成固体元素测试:
GameObject prefab = Assets.GetPrefab(ModElements.AuroraCrystal.CreateTag());
GameUtil.KInstantiate(prefab, position, Grid.SceneLayer.Ore).SetActive(true);生成液体/气体测试:
SimMessages.AddRemoveSubstance(
cell,
ModElements.AuroraCrystalGas,
CellEventLogger.Instance.ElementEmitted,
1f, // 质量(kg)
300f, // 温度(K)
byte.MaxValue, // 病菌索引
0); // 病菌数量生成检查清单:
- feature yaml 是否复制到 Mod 输出目录的
worldgen/features/下。 - subworld 是否引用了 feature,路径是否对得上。
- world 是否引用了 subworld,
minCount是否大于 0。 element名是否和custom_elements.yaml里的elementId完全一致。- 温度单位是开尔文,不是摄氏度。
- 测试一定要开新档。
最常见的问题是写了一整套 feature + subworld + world,但少了一层引用导致生成失败。建议先做一个简单的 Blob feature,在已有的 SandstoneStart subworld 里引用它试试,确认元素能刷出来再扩展。
常见问题
新元素在地图里完全没有 — 逐层检查引用链:world → subworld → feature → element ID。通常某一层的路径拼错了。
生成了但质量不对 — massOverride 是每格 kg。如果没写 massOverride,默认值和元素定义的 defaultMass 有关。检查 yaml 缩进——overrides 块必须和 choices 同级。
元素生成了但温度是 0K(绝对零度) — temperatureOverride 没生效,或者温度写了摄氏度值(比如 20 当成 20°C,实际被当作 20K)。
世界生成报错 — 看 Player.log,搜索目标元素名或 feature 路径。日志通常会告诉你哪个 yaml 解析失败。
想覆盖原版地图但不想动 Steam 源文件 — Mod 的 worldgen 目录文件会合并到原版资源里,同名文件 Mod 版优先。创建新的 world 文件引用你的 subworld 即可,不需要改原版 world 文件。