Ducky.Sdk 0.1.8

dotnet add package Ducky.Sdk --version 0.1.8
                    
NuGet\Install-Package Ducky.Sdk -Version 0.1.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ducky.Sdk" Version="0.1.8">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ducky.Sdk" Version="0.1.8" />
                    
Directory.Packages.props
<PackageReference Include="Ducky.Sdk">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ducky.Sdk --version 0.1.8
                    
#r "nuget: Ducky.Sdk, 0.1.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ducky.Sdk@0.1.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ducky.Sdk&version=0.1.8
                    
Install as a Cake Addin
#tool nuget:?package=Ducky.Sdk&version=0.1.8
                    
Install as a Cake Tool

Ducky.Sdk

中文 | English

一个用于为"Escape from Duckov"游戏开发 Mod 的综合性 .NET SDK。

License: MIT .NET NuGet NuGet Downloads MyGet GitHub Stars GitHub Issues GitHub Pull Requests PRs Welcome

功能特性

  • 🚀 自动化构建管道 - 构建时自动部署到游戏目录
  • 🌍 智能本地化 - 基于源生成器的本地化系统,支持 CSV/文件翻译
  • 📦 单 DLL 分发 - 通过 ILRepack 自动合并程序集,无冲突部署
  • 🔧 Harmony 集成 - 可选的运行时补丁支持,无缝依赖管理
  • 🎨 自动生成资源 - 自动生成 Mod 元数据和预览图
  • 📝 强类型开发 - 完整的 IntelliSense 支持和编译时验证
  • 🔄 源码分发 - SDK 以源代码形式分发,避免版本冲突

快速开始

前置要求

  • .NET SDK 9.0 或更高版本
  • 已安装"Escape from Duckov"游戏
  • Steam 安装目录(用于自动部署)

安装

  1. 在项目根目录创建 Local.props(git 忽略):
<Project>
  <PropertyGroup>
    <SteamFolder>/path/to/your/steam/</SteamFolder>
  </PropertyGroup>
</Project>
  1. 配置你的 Mod 项目:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <ModName>MyAwesomeMod</ModName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Ducky.Sdk" Version="*">
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>
</Project>

CI/CD 环境配置

在持续集成环境(如 GitHub Actions、Azure Pipelines)中,无需安装 Steam 即可构建 Mod。通过环境变量直接指定关键路径:

# GitHub Actions 示例
env:
  ManagedDirectory: /opt/game-assemblies/Managed/
  ModsDirectory: /tmp/mod-output/

或通过 MSBuild 参数传递:

dotnet build -p:ManagedDirectory=/path/to/managed/ -p:ModsDirectory=/path/to/mods/

CI 构建优势:

  • 无需 Steam 安装
  • 无需游戏文件
  • 灵活的输出路径配置
  • 自动跳过 SteamFolder 验证(检测 CI 环境变量)

你的第一个 Mod

创建 ModBehaviour.cs 文件:

using Ducky.Sdk.Logging;
using Ducky.Sdk.ModBehaviours;

namespace MyAwesomeMod;

public class ModBehaviour : ModBehaviourBase
{
    protected override void ModEnabled()
    {
        Log.Info("我的超棒 Mod 已启用!");
        // 在这里编写初始化代码
    }

    protected override void ModDisabled()
    {
        Log.Info("我的超棒 Mod 已禁用!");
        // 在这里编写清理代码
    }
}

构建并运行:

dotnet build
# 你的 Mod 会自动部署到游戏目录!

包发布渠道

Ducky.Sdk 通过以下渠道发布:

NuGet.org (稳定版)

MyGet (预览版)

双重发布机制

  • 容错设计: 即使其中一个发布渠道失败,另一个仍会继续发布
  • 同步版本: 标签版本会同时发布到两个渠道
  • 开发版本: main 分支的构建版本优先在 MyGet 上提供

推荐使用方式

  • 生产环境: 使用 NuGet.org 稳定版本
  • 开发测试: 使用 MyGet 预览版本以获取最新功能
  • 体验测试: 在项目中指定预发布版本:<PackageReference Include="Ducky.Sdk" Version="*" />

核心概念

ModBehaviour 模式

每个 Mod 都继承 ModBehaviourBase,它提供:

  • 生命周期钩子ModEnabled()ModDisabled()
  • 自动初始化:日志记录、本地化和 buff 注册
  • Mod 身份:访问 Mod 名称、ID 和 Steam 创意工坊元数据
public class ModBehaviour : ModBehaviourBase
{
    protected override void ModEnabled()
    {
        // 当 Mod 被加载时调用
        // 初始化系统、注册事件、应用补丁
    }

    protected override void ModDisabled()
    {
        // 当 Mod 被卸载时调用
        // 清理资源、移除补丁、注销事件
    }
}

本地化系统

SDK 使用独特的双类模式实现类型安全的本地化:

1. 定义键(LK.cs)
using Ducky.Sdk.Attributes;

[LanguageSupport("en", "zh", "fr")]
public static class LK
{
    public static class UI
    {
        public const string Welcome = "欢迎使用我的 Mod!";
        public const string Settings = "设置";
        
        [TranslateFile("md")]
        public const string Documentation = "文档";
    }
}
2. 使用生成的属性(自动生成的 L.cs)
using Ducky.Sdk.Localizations;

// SDK 会生成一个匹配的 L 类及其属性
Log.Info(L.UI.Welcome);        // 返回本地化字符串
Log.Info(L.UI.Documentation);  // 返回 Documentation.md 的内容
3. 管理翻译

翻译存储在 assets/Locales/

assets/
  Locales/
    en.csv         # 英文翻译
    zh.csv         # 中文翻译
    en/
      Documentation.md  # 英文长文本内容
    zh/
      Documentation.md  # 中文长文本内容

CSV 格式:

Key,Value
欢迎使用我的 Mod!,欢迎使用我的 Mod!
设置,设置
文档,Documentation.md
4. 多目录本地化支持

通过 LocalizationAssetsDir 属性,您可以指定多个本地化资源目录:

<PropertyGroup>
  <LocalizationAssetsDir>assets/Locales;shared-locales;external-translations</LocalizationAssetsDir>
</PropertyGroup>

当指定多个目录时:

  • 每个目录都应包含相同结构的 CSV 文件
  • UpdateLocalesCsv target 会为所有目录生成和验证翻译文件
  • 其他资源文件仍使用 AssetsDir 指定的目录

配置管理

存储和检索 Mod 设置:

using Ducky.Sdk.Options;

// 每个 Mod 的配置(隔离存储)
ModOptions.ForThis.Set("volume", 0.8);
var volume = ModOptions.ForThis.Get("volume", 1.0);

// 共享配置(跨所有 Mod)
ModOptions.ForAllMods.Set("globalSetting", "value");

日志记录

使用 LibLog 进行结构化日志记录:

using Ducky.Sdk.Logging;

Log.Info("玩家加入:{PlayerName}", playerName);
Log.Warn("生命值过低:{Health}", health);
Log.Error(exception, "加载资源失败:{ResourceId}", resourceId);

高级功能

MessageHub 跨 Mod 通信

SDK 集成了 MessageHub 功能,允许 mod 之间进行通信,无需安装额外的 host mod。

自动 Host 功能
public class MyModBehaviour : ModBehaviourBase
{
    // 默认启用,可以选择禁用
    protected override bool EnableMessageHubHost { get; set; } = true;

    protected override void ModEnabled()
    {
        // 检查此 mod 是否是 host
        if (IsMessageHubHost)
        {
            Log.Info("此 Mod 是 MessageHub Host!");
        }

        // 注册为消息接收方
        var proxy = ModHttpV1Proxy.CreateFromSingleton();
        proxy.RegisterClient("MyMod", async (fromMod, contentType, body) =>
        {
            Log.Info($"收到来自 {fromMod} 的消息: {body}");
            // 处理消息...
        });
    }
}
发送消息到其他 Mod
var proxy = ModHttpV1Proxy.CreateFromSingleton();
await proxy.Notify("MyMod", "TargetModName", "custom_event", "Hello World!");
特性
  • 无需额外安装 - 自动集成在 SDK 中
  • 自动 Host 检测 - 第一个启动的 mod 成为 host
  • 向后兼容 - 与现有代码完全兼容
  • 生命周期管理 - Host 会持续运行,即使创建它的 mod 已禁用

Harmony 运行时补丁

启用运行时方法补丁以实现高级 Mod:

<PropertyGroup>
  <ModName>MyAwesomeMod</ModName>
  <IncludeHarmony>true</IncludeHarmony>
</PropertyGroup>

使用 Harmony 补丁:

using HarmonyLib;

public class ModBehaviour : ModBehaviourBase
{
    private Harmony _harmony;
    
    protected override void ModEnabled()
    {
        _harmony = new Harmony("com.myname.mymod");
        _harmony.PatchAll();
    }
    
    protected override void ModDisabled()
    {
        _harmony?.UnpatchAll();
    }
}

[HarmonyPatch(typeof(Player), nameof(Player.TakeDamage))]
public static class Player_TakeDamage_Patch
{
    static void Prefix(Player __instance, ref float damage)
    {
        Log.Info("玩家受到伤害:{Damage}", damage);
        damage *= 0.5f; // 伤害减少 50%
    }
}

程序集合并

默认情况下,SDK 会将所有依赖项合并到单个 DLL:

<PropertyGroup>
  
  <EnableILRepack>true</EnableILRepack>
  
  
  <EnableILRepack>false</EnableILRepack>
</PropertyGroup>

优点:

  • ✅ 单文件分发
  • ✅ Mod 之间无版本冲突
  • ✅ 内部化依赖项(无命名空间污染)
  • ✅ 更小的部署占用空间

多项目 Mod

将复杂的 Mod 组织成多个项目:

共享库项目MyMod.Common.csproj):

<PropertyGroup>
  <IsModLib>true</IsModLib>
  <AssetsDir>$(SolutionDir)/MyMod/assets</AssetsDir>
</PropertyGroup>

入口项目MyMod.csproj):

<PropertyGroup>
  <ModName>MyMod</ModName>
  <ExcludeSdkLib>true</ExcludeSdkLib>
</PropertyGroup>

<ItemGroup>
  <ProjectReference Include="../MyMod.Common/MyMod.Common.csproj" />
</ItemGroup>
IsModLib 行为差异

共享库项目IsModLib=true)会跳过以下自动化任务:

  • ❌ 预览图片(preview.png)生成
  • ❌ Mod 元数据(info.ini)生成
  • ❌ 自动部署到游戏目录
  • ❌ ILRepack 程序集合并
  • ❌ 依赖文件复制

保留的功能

  • ✅ 本地化处理(字符串提取和 CSV 更新)
  • ✅ 编译和程序集生成

最终发布 Mod 项目IsModLib=false 或未设置)会执行所有自动化任务。

项目属性说明
  • IsModLib=true: 标记项目为共享库,跳过非必要的自动化任务
  • ExcludeSdkLib=true: 排除 SDK 源代码编译(用于入口项目,避免重复编译)

自动生成资源

SDK 会自动生成:

  1. info.ini - 基本 Mod 元数据(名称、显示名称、描述)
  2. preview.png - 基于 Mod 名称的 256x256 identicon
  3. publishedFileId - Steam 创意工坊 ID 同步

开发期间禁用自动部署:

<PropertyGroup>
  <DeployMod>false</DeployMod>
</PropertyGroup>

项目结构

MyMod/
├── MyMod.csproj           # 主 Mod 项目
├── ModBehaviour.cs        # Mod 入口点
├── LK.cs                  # 本地化键
├── Local.props            # Git 忽略的本地配置
└── assets/
    ├── info.ini           # Mod 元数据
    ├── preview.png        # Mod 图标
    ├── description.md     # 详细描述
    └── Locales/
        ├── en.csv         # 英文翻译
        ├── zh.csv         # 中文翻译
        └── ...

SDK 开发

本地构建 SDK

  1. 打包到本地源:
./scripts/packToLocal.sh --version 0.0.1
  1. 使用新 SDK 重建示例:
./scripts/rebuild_samples.sh
  1. 获取游戏依赖:
./scripts/fetch_build_dependency.sh

测试更改

Samples/ 目录包含集成测试项目:

  • Ducky.SingleProject - 单项目 Mod 模板
  • Ducky.EntranceMod - 带共享库的多项目 Mod
  • Ducky.TryHarmony - Harmony 补丁示例

运行 ./scripts/rebuild_samples.sh 验证端到端 SDK 工作流程。

仓库结构

Ducky.Sdk/
├── Sdk/                           # SDK 开发工作区
│   ├── SDKlibs/
│   │   ├── Ducky.Sdk/            # 核心 NuGet 包
│   │   │   ├── Ducky.Sdk.nuspec  # 包清单
│   │   │   ├── Ducky.Sdk.props   # MSBuild 属性
│   │   │   ├── Ducky.Sdk.targets # 构建目标
│   │   │   └── scripts/*.csx     # 自动化脚本
│   │   └── Ducky.Sdk.Lib/        # 共享库(以源码分发)
│   ├── Ducky.Sdk.Analyser/       # Roslyn 源生成器
│   └── Tests/                     # 单元测试
├── Samples/                       # 示例 Mod 项目
│   ├── Ducky.SingleProject/
│   ├── Ducky.EntranceMod/
│   └── Ducky.TryHarmony/
├── scripts/                       # 构建自动化
│   ├── packToLocal.sh            # 打包 SDK 到本地源
│   ├── rebuild_samples.sh        # 使用新 SDK 重建示例
│   └── fetch_build_dependency.sh # 下载游戏程序集
└── duckylocal/                   # 本地 NuGet 源

配置参考

MSBuild 属性

属性 默认值 描述
ModName (必需) Mod 标识符和输出 DLL 名称
SteamFolder - Steam 安装路径
DuckovFolder 计算得出 游戏目录(从 SteamFolder 自动计算)
ManagedDirectory 计算得出 游戏托管程序集目录(可显式设置用于 CI 环境)
ModsDirectory 计算得出 Mod 部署目标目录(可显式设置用于 CI 环境)
DeployMod true 启用自动部署到游戏
EnableILRepack true 将程序集合并到单个 DLL
IncludeHarmony false 包含 Harmony 用于运行时补丁
AssetsDir assets/ 自定义资源目录路径(用于一般资源)
LocalizationAssetsDir $(AssetsDir) 本地化资源目录路径(用于 UpdateLocalesCsv target)
ExcludeSdkLib true 排除 SDK 源代码编译(用于入口项目)
IsModLib false 将项目标记为共享库(跳过图片生成、部署、ILRepack 等自动化任务,仅保留本地化处理)
AssetsDir vs LocalizationAssetsDir

AssetsDirLocalizationAssetsDir 有不同的用途:

  • AssetsDir: 用于一般资源(如 info.inipreview.png 等),期望为单一路径
  • LocalizationAssetsDir: 专用于本地化资源,支持多个目录(用分号分隔)

使用场景:


<PropertyGroup>
  <AssetsDir>assets</AssetsDir>
  
</PropertyGroup>


<PropertyGroup>
  <AssetsDir>assets</AssetsDir>
  <LocalizationAssetsDir>locales;shared-locales</LocalizationAssetsDir>
</PropertyGroup>

本地化属性

[LanguageSupport(...)]

指定支持的语言:

[LanguageSupport("en", "zh", "fr", "de", "ja")]
public static class LK { ... }

使用 "all" 生成所有支持语言的文件:

[LanguageSupport("all")]
public static class LK { ... }

使用 "all" 时支持的语言:de, en, es, fr, ja, ko, pt, ru, zh-hant, zh

混合使用 "all" 和额外语言:

[LanguageSupport("all", "custom-lang")]
public static class LK { ... }
[TranslateFile][TranslateFile("ext")]

在外部文件中存储翻译:

[TranslateFile]           // 使用 .txt 扩展名
public const string Help = "帮助文本";

[TranslateFile("md")]     // 使用 .md 扩展名
public const string ReadMe = "说明内容";

故障排除

"SteamDir property must be set"

本地开发: 在项目根目录创建 Local.props,填写 Steam 安装路径:

<Project>
  <PropertyGroup>
    <SteamFolder>/path/to/steam/</SteamFolder>
  </PropertyGroup>
</Project>

CI 环境: 设置 ManagedDirectoryModsDirectory 环境变量:

env:
  ManagedDirectory: /path/to/managed/
  ModsDirectory: /path/to/mods/

或通过 MSBuild 参数:

dotnet build -p:ManagedDirectory=/path/to/managed/ -p:ModsDirectory=/path/to/mods/

NuGet 缓存过期

清除所有缓存并重建:

./scripts/rebuild_samples.sh --clear-all-caches

或手动清除:

dotnet nuget locals all --clear
rm -rf ~/.nuget/packages/ducky.sdk/

缺少游戏程序集

下载所需的游戏 DLL:

./scripts/fetch_build_dependency.sh

Mod 未部署

  1. 验证 $(DuckovFolder) 路径存在
  2. 检查 $(DeployMod) 是否设置为 false
  3. 确保对游戏目录有写入权限

CSV 中缺少本地化键

SDK 会验证 CSV 文件包含所有键。运行:

dotnet build

检查构建输出中的验证错误。

示例

查看 Samples/ 目录获取完整示例:

贡献

欢迎贡献!请:

  1. Fork 仓库
  2. 创建功能分支
  3. 进行更改
  4. 使用 ./scripts/rebuild_samples.sh 测试
  5. 提交 Pull Request

许可证

本项目采用 MIT 许可证 - 详见 LICENSE 文件。

致谢

支持


用 ❤️ 为 Escape from Duckov Mod 社区打造

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.8 101 1/6/2026
0.1.8-dev.1 47 1/6/2026
0.1.7 96 1/6/2026
0.1.7-dev.4 57 1/6/2026
0.1.7-dev.3 53 1/6/2026
0.1.7-dev.2 535 12/1/2025
0.1.7-dev.1 439 12/1/2025
0.1.6 194 11/27/2025
0.1.6-dev.21 141 11/27/2025
0.1.6-dev.20 145 11/27/2025
0.1.6-dev.19 152 11/27/2025
0.1.6-dev.18 146 11/27/2025
0.1.6-dev.17 159 11/26/2025
0.1.6-dev.16 149 11/25/2025
0.1.6-dev.15 145 11/25/2025
0.1.6-dev.14 145 11/25/2025
0.1.6-dev.13 145 11/25/2025
0.1.6-dev.12 151 11/25/2025
0.1.6-dev.11 152 11/25/2025
0.1.6-dev.10 148 11/25/2025
Loading failed