Skip to content

验证环境

本页内容已按 Build 740622 对应的本机 Managed DLL 和项目配置检查;尚未在游戏内完成运行验证。

第一个 Mod

先做一个最小改动:把原版电解器的工作功耗改成 1 W。这个例子不新增建筑、不改存档,适合确认编译、加载和 Harmony 补丁都正常。

项目结构

仓库里已经有完整示例:

text
examples/FirstMod/
├── FirstMod.csproj
├── Mod.cs
├── STRINGS.cs
├── mod.yaml
└── mod_info.yaml

所有示例共用 examples/Directory.Build.props。它从 GameManagedDir 读取游戏 DLL,不依赖固定 Steam 路径。

两个 YAML 文件不要混用:

mod.yaml 放显示信息:

yaml
title: "ONI Tutorial First Mod"
description: "The smallest compilable ONI Mod example."
staticID: "ONITutorial.FirstMod"

mod_info.yaml 放加载和版本信息:

yaml
minimumSupportedBuild: 740622
version: 1.0.0
APIVersion: 2

740622 是当前示例的测试 Build。换版本测试后,改成实际验证过的数字。没有 DLC 限制时,不要添加 DLC 字段。

入口和补丁

Mod 入口继承 UserMod2。完整代码在 examples/FirstMod/Mod.cs

csharp
using HarmonyLib;
using KMod;
using UnityEngine;

namespace ONITutorial.FirstMod
{
    public sealed class Mod : UserMod2
    {
        public override void OnLoad(Harmony harmony)
        {
            base.OnLoad(harmony);
            Debug.Log("[ONITutorial.FirstMod] Loaded");
        }

        [HarmonyPatch(typeof(ElectrolyzerConfig), nameof(ElectrolyzerConfig.CreateBuildingDef))]
        private static class ElectrolyzerPatch
        {
            private static void Postfix(ref BuildingDef __result)
            {
                if (__result != null)
                    __result.EnergyConsumptionWhenActive = 1f;
            }
        }
    }
}

补丁打在 ElectrolyzerConfig.CreateBuildingDef,因为电解器功耗是在创建 BuildingDef 时设置的。原版方法先完成,Postfix 再修改返回值:

csharp
[HarmonyPatch(typeof(ElectrolyzerConfig), nameof(ElectrolyzerConfig.CreateBuildingDef))]
private static class ElectrolyzerPatch
{
    private static void Postfix(ref BuildingDef __result)
    {
        if (__result != null)
            __result.EnergyConsumptionWhenActive = 1f;
    }
}

选择补丁时记住三点:

  • 修改返回对象:通常用 Postfix
  • 修改参数或阻止原方法:考虑 Prefix
  • 记录异常和清理:使用 Finalizer

只有普通 Prefix/Postfix 无法完成需求时,才使用 Transpiler。

编译

在仓库根目录执行:

powershell
$managed = "D:\SteamLibrary\steamapps\common\Oxygen Not Included\OxygenNotIncluded_Data\Managed"

dotnet build .\examples\FirstMod\FirstMod.csproj `
  --configuration Debug `
  -p:GameManagedDir=$managed

把路径换成自己的游戏安装目录。也可以先设置环境变量:

powershell
$env:ONI_GAME_MANAGED_DIR = $managed

编译成功后,输出在:

text
examples/FirstMod/bin/

复制到游戏

开发时使用 mods/Dev

powershell
$modDir = "$env:USERPROFILE\Documents\Klei\OxygenNotIncluded\mods\Dev\ONITutorial.FirstMod"
New-Item -ItemType Directory -Force $modDir | Out-Null
Copy-Item .\examples\FirstMod\bin\* $modDir -Recurse -Force

不要只复制 DLL。mod.yamlmod_info.yaml 也要在同一个目录。

同一个 Mod 不要同时打开 Steam、Local 和 Dev 版本,否则很难判断游戏加载的是哪一份。

游戏内验证

  1. 启动游戏并启用 ONI Tutorial First Mod
  2. 打开测试存档,找到电解器。
  3. 确认工作功耗变为 1 W
  4. 如果没有变化,查看日志:
text
%USERPROFILE%\AppData\LocalLow\Klei\Oxygen Not Included\Player.log

搜索 ONITutorial.FirstModHarmonyException

编译成功只说明代码能生成 DLL,不代表游戏一定加载了正确目录。每次修改都按“编译 → 复制 → 启动 → 验证”的顺序测试。

常见问题

现象先检查
找不到 KModBuildingDefGameManagedDir 是否指向 Managed
Mod 列表里没有项目DLL、两个 YAML 是否在同一目录
有加载日志但功耗没变方法名、补丁签名和复制的 DLL
修改后仍是旧结果是否启用了另一份 Steam/Local/Dev Mod
启动时报类型或方法异常游戏 Build 和编译时 DLL 是否一致

接下来学什么