1. 缺氧 worldgen 地图 mod 开发:从 YAML 骨架到 VSCode 配置落地
《缺氧》的地图 mod 开发,本质上是跟一堆 YAML 文件打交道。你想改荒芜星球的生态分布、加几个冷蒸、把底部岩浆换成冰核,甚至做一张全新世界,最终都要落到worldgen/worlds和worldgen/subworlds这两个目录里的 YAML 上。它适合已经会打开游戏目录、能看懂 key-value 结构、但还没把整套配置串起来的开发者。我试过在 VSCode 里直接改Badlands.yaml,改完丢进 mod 文件夹,进游戏一看生态全乱——问题往往不在 YAML 本身,而在配置骨架没搭对、路径没对齐、或者 Key 通道没统一管理。
这篇就按“能跟做”的节奏来:先讲清楚 worldgen 配置到底在改什么,再把 TaoToken 的 Key/API 通道接进 VSCode 工作流,然后给可复制的config.toml、settings.json和 YAML worldgen 片段,最后用实际请求验证配置生效,并把最常见的几类报错逐个拆掉。全程不需要你懂 C#,但 YAML 的缩进和大小写必须较真。
2. 原问题与场景:worldgen 配置为什么容易崩
《缺氧》的地图生成分两层:一层是subworlds,定义生态和子生态(比如砂岩、丛林、岩浆、太空);另一层是worlds,定义某个星球用哪些生态、放在什么位置、生成多少泉和遗迹。你打开OxygenNotIncluded_Data/StreamingAssets/worldgen/worlds/Badlands.yaml,看到的就是荒芜星球的完整生成规则。
新手最容易踩的坑有三个。第一,YAML 用空格缩进,混进一个 Tab 游戏直接崩,而且报错信息往往只告诉你“加载失败”,不告诉你哪一行。第二,subworldFiles里列出的生态路径必须真实存在,unknownCellsAllowedSubworlds里引用的生态也必须在上面出现过,两边对不上就加载报错。第三,泉和遗迹的替换顺序有讲究——先替换生态再替换泉,泉才不会被生态覆盖掉。
场景很具体:你在 VSCode 里打开Badlands.yaml,想加一个冰核生态,或者把geysers/generic的times从 12 改成 20。改完之后,你需要一个稳定的配置底座来管理这些改动,同时把模型调用、Key 管理、配置校验统一到一条通道上。TaoToken 在这里的角色,就是给你一个统一的 Key/API 入口,让 VSCode 里的配置文件和请求验证走同一条路,不用在多个平台之间来回切。
3. TaoToken 前置:统一 Key 与 API 通道
在动手改 YAML 之前,先把通道搭好。TaoToken 提供统一的 API 入口,你可以在官网注册后拿到 Key,然后在 VSCode 里通过配置文件管理。这样做的好处是:地图 mod 开发过程中,你可能需要调用模型来辅助生成配置片段、校验 YAML 结构、或者对比不同生态组合的效果,统一通道能省掉反复切换的麻烦。
先拿 Key。打开官网https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册后在控制台创建 API Key。控制台地址是https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite,API Keys 管理页在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite。Key 拿到后先别急着写进代码,下面用配置文件管理。
API 基础地址是https://taotoken.net/api,注意这个地址不加 UTM 参数,直接用于请求。模型对话入口在https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite,接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite。如果你后续要做长期编码或 Agent 类工作,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite。
注意:Key 只存在本地配置文件里,不要提交到 Git,也不要在 YAML 地图文件里写任何 Key 信息。地图 mod 的 YAML 只负责游戏逻辑,跟 API 通道分开管理。
4. 可复制配置:config.toml 与 settings.json 骨架
VSCode 里管理 TaoToken 配置,推荐用config.toml存 Key 和基础地址,用settings.json存编辑器层面的行为。下面两个骨架可以直接复制,改掉 Key 就能用。
先建工作目录,比如D:/ONI_Mods/dev,在里面放配置文件。config.toml内容如下:
# TaoToken 统一通道配置 # 不要把此文件提交到公开仓库 [api] base_url = "https://taotoken.net/api" api_key = "sk-你的Key写在这里" timeout = 60 [model] default = "claude-sonnet" max_tokens = 4096 [workspace] oni_worldgen_path = "D:/Steam/steamapps/common/OxygenNotIncluded/OxygenNotIncluded_Data/StreamingAssets/worldgen" mod_output_path = "D:/Documents/Klei/OxygenNotIncluded/mods/dev"settings.json放在.vscode目录下,用来约束 YAML 编辑行为:
{ "yaml.validate": true, "yaml.format.enable": true, "editor.insertSpaces": true, "editor.tabSize": 2, "editor.detectIndentation": false, "files.associations": { "*.yaml": "yaml" }, "yaml.schemas": { "https://taotoken.net/api/schemas/oni-worldgen.json": [ "worldgen/worlds/*.yaml", "worldgen/subworlds/**/*.yaml" ] } }这里有两个关键点。第一,editor.insertSpaces设为true、tabSize设为2,强制 YAML 用空格缩进,避免 Tab 混入。第二,files.associations确保.yaml文件被识别为 YAML,语法高亮和校验才会生效。yaml.schemas那行是可选的高级用法,如果你暂时没有 schema 文件,可以先删掉,不影响基础编辑。
接下来是 YAML worldgen 片段。以荒芜星球为例,下面是一个可复制的最小骨架,保留了核心字段,你可以在此基础上加生态:
name: STRINGS.WORLDS.BADLANDS.NAME description: STRINGS.WORLDS.BADLANDS.DESCRIPTION asteroidIcon: Asteroid_badlands worldTraitScale: 1 worldsize: X: 256 Y: 384 layoutMethod: PowerTree subworldFiles: - name: subworlds/sandstone/SandstoneStart - name: subworlds/sandstone/SandstoneMiniMetal - name: subworlds/sandstone/SandstoneMiniWater - name: subworlds/jungle/Jungle minCount: 2 - name: subworlds/frozen/Frozen minCount: 3 - name: subworlds/magma/Bottom - name: subworlds/oil/OilPockets minCount: 4 - name: subworlds/space/Space - name: subworlds/space/Surface - name: subworlds/rust/Rust - name: subworlds/barren/BarrenGranite startSubworldName: subworlds/sandstone/SandstoneStart startingBaseTemplate: bases/sandstoneBase startingBasePositionHorizontal: min: 0.4 max: 0.5 startingBasePositionVertical: min: 0.45 max: 0.55 seasons: - MeteorShowers worldTraitRules: - min: 2 max: 4 unknownCellsAllowedSubworlds: - tagcommand: Default command: Replace subworldNames: - subworlds/sandstone/SandstoneStart - tagcommand: DistanceFromTag tag: AtStart minDistance: 1 maxDistance: 2 command: Replace subworldNames: - subworlds/barren/BarrenGranite - subworlds/jungle/Jungle - subworlds/rust/Rust - subworlds/sandstone/SandstoneMiniMetal - subworlds/sandstone/SandstoneMiniWater - tagcommand: AtTag tag: AtDepths command: Replace subworldNames: - subworlds/magma/Bottom - tagcommand: DistanceFromTag tag: AtDepths minDistance: 1 maxDistance: 2 command: Replace subworldNames: - subworlds/barren/BarrenGranite - subworlds/oil/OilPockets - tagcommand: AtTag tag: AtSurface command: Replace subworldNames: - subworlds/space/Space - tagcommand: DistanceFromTag tag: AtSurface minDistance: 1 maxDistance: 2 command: Replace subworldNames: - subworlds/space/Surface worldTemplateRules: - names: - poi/jungle/geyser_steam listRule: TryOne priority: 100 allowedCellsFilter: - command: Replace zoneTypes: [ToxicJungle] - names: - poi/jungle/geyser_methane - poi/jungle/geyser_chlorine listRule: TryOne priority: 100 allowedCellsFilter: - command: Replace zoneTypes: [ToxicJungle] - names: - poi/oil/small_oilpockets_geyser_a - poi/oil/small_oilpockets_geyser_b - poi/oil/small_oilpockets_geyser_c listRule: TryOne times: 3 allowDuplicates: true priority: 100 allowedCellsFilter: - command: Replace zoneTypes: [OilField] - names: - geysers/generic listRule: TryOne times: 12 ruleId: GenericGeysers allowDuplicates: true allowedCellsFilter: - command: Replace tagcommand: NotAtTag tag: NoGlobalFeatureSpawning这个骨架里,subworldFiles列出的每个生态路径都必须在worldgen/subworlds下真实存在。unknownCellsAllowedSubworlds里的subworldNames也必须在subworldFiles里出现过,两边是双向约束。worldTemplateRules负责泉和遗迹,geysers/generic表示从全部泉里抽样,times: 12是抽样数量。
5. 验证请求与成功结果
配置写完后,先别急着进游戏。在 VSCode 里用 TaoToken 的 API 做一次请求验证,确认通道通、Key 有效、返回正常。用 curl 或者 Python 都行,下面给 curl 示例:
curl -X POST "https://taotoken.net/api/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "claude-sonnet", "messages": [ {"role": "user", "content": "请检查以下 YAML 是否有缩进错误:\nsubworldFiles:\n - name: subworlds/sandstone/SandstoneStart\n - name: subworlds/jungle/Jungle\n minCount: 2"} ], "max_tokens": 512 }'如果返回里有正常的choices内容,说明 Key 和通道都没问题。如果返回 401,检查 Key 是否写对;返回 404,检查base_url是否漏了/api;返回超时,把timeout调大。
通道验证通过后,再验证 YAML 本身。在 VSCode 里打开Badlands.yaml,看底部状态栏有没有 YAML 语法错误提示。如果没有报错,把文件复制到 mod 目录:
# 假设 mod 目录结构如下 # D:/Documents/Klei/OxygenNotIncluded/mods/dev/MyWorldMod/ # mod.yaml # mod_info.yaml # worldgen/worlds/Badlands.yaml mkdir -p "D:/Documents/Klei/OxygenNotIncluded/mods/dev/MyWorldMod/worldgen/worlds" cp "D:/ONI_Mods/dev/Badlands.yaml" "D:/Documents/Klei/OxygenNotIncluded/mods/dev/MyWorldMod/worldgen/worlds/Badlands.yaml"mod.yaml内容:
title: MyWorldMod description: 自定义荒芜星球生态与泉分布mod_info.yaml内容:
supportedContent: VANILLA_ID minimumSupportedBuild: 489681 version: 1.0.0 APIVersion: 1进游戏,打开 mod 选项,启用MyWorldMod,然后开一局荒芜。如果地图能正常加载,说明配置生效。如果加载失败,看游戏日志里的报错行号,回到 YAML 里对应位置检查。
6. 本篇常见错排查
6.1 YAML 缩进报错:Tab 混入或层级不对
游戏崩溃最常见的原因就是 YAML 里混了 Tab。VSCode 默认可能用 Tab 缩进,你需要在settings.json里强制insertSpaces: true。另外,subworldFiles下的- name和minCount必须对齐,minCount比name多缩进两个空格。如果层级错了,游戏会报“加载 worldgen 失败”,但不告诉你哪一行。
排查动作:在 VSCode 里按Ctrl+Shift+P,输入Convert Indentation to Spaces,把整个文件转成空格缩进。然后看行号旁边有没有红色波浪线。
6.2 生态路径不存在:subworldFiles 与 subworldNames 对不上
subworldFiles里写的subworlds/jungle/Jungle,必须在OxygenNotIncluded_Data/StreamingAssets/worldgen/subworlds/jungle/Jungle.yaml存在。如果路径写错,或者unknownCellsAllowedSubworlds里引用了没在subworldFiles里出现过的生态,加载就会报错。
排查动作:在 VSCode 里用Ctrl+P快速打开文件,输入subworlds/jungle/Jungle,看能不能定位到。定位不到就是路径错了。然后把unknownCellsAllowedSubworlds里所有subworldNames跟subworldFiles里的name逐个比对,确保双向一致。
6.3 泉和遗迹被生态覆盖:替换顺序问题
如果你先替换泉和遗迹,再替换生态,泉会被生态贴图覆盖掉。正确顺序是先替换生态,再替换泉和遗迹。在 YAML 里,unknownCellsAllowedSubworlds在前,worldTemplateRules在后,这个顺序不能反。
排查动作:检查Badlands.yaml里unknownCellsAllowedSubworlds是否在worldTemplateRules之前。如果反了,把两块整体调换位置。
6.4 mod 不生效:目录结构或 mod_info.yaml 缺失
mod 目录必须包含mod.yaml和mod_info.yaml,否则游戏会显示版本错误。地图文件的目录结构必须跟原游戏一致,比如worldgen/worlds/Badlands.yaml,不能直接丢在 mod 根目录。
排查动作:确认 mod 目录下有mod.yaml、mod_info.yaml、worldgen/worlds/Badlands.yaml三个文件。mod_info.yaml里minimumSupportedBuild写489681,supportedContent写VANILLA_ID。
6.5 API 请求 401/404:Key 或 base_url 写错
401 通常是 Key 无效或没带Bearer前缀。404 通常是base_url写成了https://taotoken.net而漏了/api。超时则是网络或timeout设置太小。
排查动作:用 curl 重新请求一次,把-H "Authorization: Bearer sk-你的Key"里的 Key 换成新创建的。base_url确认是https://taotoken.net/api。如果还不行,去 API Keys 页面重新生成一个 Key。
7. 继续往下走:把配置底座用起来
地图 mod 的配置底座搭好之后,你可以做的事情就多了。比如把geysers/generic的times从 12 改成 20,进游戏数泉的数量;或者把subworlds/magma/Bottom换成subworlds/frozen/CO2Lakes,看底部变成冰核之后生态怎么分布。每次改完,用 VSCode 的 YAML 校验先过一遍,再复制到 mod 目录,进游戏验证。
如果你后续要做更复杂的 worldgen 组合,或者想让模型帮你批量生成生态配置片段,可以走模型对话入口:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite。长期做编码和 Agent 类工作的话,Coding Plan 在https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite。接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite,Key 管理在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite。
最后提醒一句:改任何游戏原文件之前先备份。mod 目录里的文件是独立的,但如果你直接改StreamingAssets下的原文件,游戏更新后会被覆盖,而且出问题不好回滚。把改动都放在 mod 目录里,用mod.yaml和mod_info.yaml管理版本,这样最稳。