YummiHarness
Safe patch injection for DSP mods: patch only if the game method is unchanged. | 戴森球计划安全注入前置:目标方法与原版一致才打补丁
| Last updated | a day ago |
| Total downloads | 329 |
| Total rating | 0 |
| Categories | Environment |
| Dependency string | cat_yummi-YummiHarness-0.2.1 |
| Dependants | 3 other packages depend on this package |
This mod requires the following mods to function
README
YummiHarness
https://github.com/cat-yummi-dspmod/DSP-YummiHarness
中文
戴森球计划的"安全注入"前置 mod + 命令行工具。 补丁只在目标方法与原版 IL 完全一致时才会应用;失败只跳过这一个补丁;所有问题在主菜单一次性弹窗,详情写入日志。
它做什么
- 指纹校验:对目标方法的 IL 做规范化后哈希。游戏更新后方法有任何变化,对应补丁自动跳过,不影响 mod 的其他功能。
- 失败记录:patch 失败时记录该 mod,并在主菜单弹窗:"xxx 部分 patch 失败,详情请看日志"。可通过
PatchOptions.OnFailure返回false关闭记录(默认记录)。 - 互斥登记:
Harness.RegisterConflict(...),对方存在时和 patch 失败合并在同一个弹窗。 - 自定义兼容性告警:
Harness.RegisterCompatibilityAdvisory(...),当指定的几个 mod 都已加载时,在主菜单弹窗提示(例如「A 与 B 在某功能上兼容性较差,可能引发 xxx」);详情可写进日志。与互斥不同:不强制停用 mod。 - 同函数警告:多个 mod 修改同一个游戏函数时给出警告(含没用本 mod 的 mod)。后打补丁的一方可用
PatchOptions.OnShared决定自己是否仍然应用;Harness.DeclareCompatible(a, b)可对已知安全的组合静音;配置项WarnSharedTargets可整体关闭。 - 语言:弹窗和详细日志使用游戏语言。补丁发生的那一刻游戏语言通常还没加载,那一行日志退回系统语言。
mod 作者怎么用
[BepInDependency("com.yummi.dsp.yummiharness")]
...
Harness.RegisterConflict("MyMod", "other.guid", "OtherMod");
Harness.RegisterCompatibilityAdvisory(
"MyMod",
new[] { "com.other.mod.guid" },
summaryZh: "MyMod 与 OtherMod 在物流统计上兼容性较差,可能出现产量显示异常",
summaryEn: "MyMod and OtherMod may disagree on logistics stats; production UI can look wrong",
detailZh: "建议关闭 OtherMod 的统计增强或只保留一个 mod 的 GameTick 逻辑。",
detailEn: "Disable the other mod's stat tweak or keep only one GameTick-related feature.",
advisoryId: "MyMod.WithOtherMod.Stats");
Harness.PatchAll(harmony, typeof(MyPatches), new PatchOptions { ModName = "MyMod" });
// 补丁方法照旧写,另加 [Guard]
[HarmonyPostfix]
[HarmonyPatch(typeof(StationComponent), nameof(StationComponent.AddItem))]
[YummiHarness.Guard("806f415ada529868")]
public static void AddItem_Postfix(...) { }
怎么获取指纹(不是 mod 作者也可以)
需要 .NET SDK,以及游戏目录里未剥离的原版 Assembly-CSharp.dll(NuGet 的 GameLibs 方法体被剥空,不能用)。
# 1. 看一个 mod(任何人写的)补丁了哪些函数、指纹是多少
.\tools\get-fingerprint.ps1 -Mod "C:\path\SomeMod.dll"
# 2. 看某个游戏函数的指纹和规范化 IL
.\tools\get-fingerprint.ps1 -Method "StationComponent::AddItem"
# 3. 游戏更新后,比较同一函数新旧版本的差异
.\tools\get-fingerprint.ps1 -Method "StationComponent::AddItem" -OldGame "D:\old\Dyson Sphere Program"
脚本会自动查找 Steam 版游戏目录(或用 -Game / 环境变量 DSP_GAME_DIR 指定),首次使用自动编译命令行工具。输出中:
[OK]与[Guard]一致;[已变化]目标方法被游戏更新改动;[找不到]方法被删除或改签名;[无Guard]该补丁没有设置指纹,行尾给出可直接粘贴的[Guard("...")]。- 有补丁已变化/找不到时,退出码为 1,可放进构建脚本。
不用脚本也行:harness scan <Mod.dll> <游戏目录>、harness dump <游戏目录> <类::方法>、harness diff <旧游戏目录> <新游戏目录> <类::方法>。
构建
dotnet build plugin -c Release -o bin # YummiHarness.dll
dotnet build cli -c Release -o bin # harness.exe
局限
- 指纹只覆盖目标方法自身,不覆盖它调用的其他方法。
- 运行时通过 BepInEx 自带的 Mono.Cecil 读取游戏 dll 的 IL。
English
A "safe injection" prerequisite mod + CLI for Dyson Sphere Program. A patch is applied only if its target method's IL is identical to vanilla. A failed patch only skips itself, and every problem is shown in one main-menu dialog with details in the log.
What it does
- Fingerprint check: the target method's IL is normalized and hashed. After a game update, any change to the method makes the matching patch skip itself; the rest of the mod keeps working.
- Failure recording: a failed patch records the mod and shows "xxx: some patches failed, see the log" in the main menu. Return
falsefromPatchOptions.OnFailureto opt out (recording is the default). - Conflict registry:
Harness.RegisterConflict(...); when the other mod is present it shares the same dialog as patch failures. - Custom compatibility advisories:
Harness.RegisterCompatibilityAdvisory(...)shows a main-menu notice when every listed plugin GUID is loaded (e.g. "Mod A and Mod B work poorly together for feature X; may cause Y"). Optional detail goes to the log. Unlike conflicts, nothing is auto-disabled. - Shared-target warning: warns when several mods patch the same game method (including mods that do not use this one). The later mod can decide in
PatchOptions.OnSharedwhether to still apply;Harness.DeclareCompatible(a, b)silences known-safe pairs; theWarnSharedTargetsconfig turns it off. - Language: dialog and detailed log use the game language. When a patch runs the game language is usually not loaded yet, so that single log line falls back to the OS language.
For mod authors
[BepInDependency("com.yummi.dsp.yummiharness")]
...
Harness.RegisterConflict("MyMod", "other.guid", "OtherMod");
Harness.RegisterCompatibilityAdvisory(
"MyMod",
new[] { "com.other.mod.guid" },
summaryZh: "MyMod 与 OtherMod 在物流统计上兼容性较差,可能出现产量显示异常",
summaryEn: "MyMod and OtherMod may disagree on logistics stats; production UI can look wrong",
detailZh: "建议关闭 OtherMod 的统计增强或只保留一个 mod 的 GameTick 逻辑。",
detailEn: "Disable the other mod's stat tweak or keep only one GameTick-related feature.",
advisoryId: "MyMod.WithOtherMod.Stats");
Harness.PatchAll(harmony, typeof(MyPatches), new PatchOptions { ModName = "MyMod" });
// write patches as usual, add [Guard]
[HarmonyPostfix]
[HarmonyPatch(typeof(StationComponent), nameof(StationComponent.AddItem))]
[YummiHarness.Guard("806f415ada529868")]
public static void AddItem_Postfix(...) { }
How to get fingerprints (you do not need to be the mod author)
You need the .NET SDK and the unstripped vanilla Assembly-CSharp.dll from the game folder (the NuGet GameLibs package has empty method bodies and cannot be used).
# 1. See which methods any mod patches and their fingerprints
.\tools\get-fingerprint.ps1 -Mod "C:\path\SomeMod.dll"
# 2. Fingerprint and normalized IL of one game method
.\tools\get-fingerprint.ps1 -Method "StationComponent::AddItem"
# 3. After a game update, diff one method between two versions
.\tools\get-fingerprint.ps1 -Method "StationComponent::AddItem" -OldGame "D:\old\Dyson Sphere Program"
The script finds the Steam install automatically (or use -Game / env var DSP_GAME_DIR) and builds the CLI on first use. In the output:
[OK]matches[Guard];[已变化](changed) the target was modified by a game update;[找不到](not found) the method was removed or its signature changed;[无Guard](no Guard) the patch has no fingerprint, and a paste-ready[Guard("...")]is printed at the end of the line.- Exit code is 1 when a patch changed or is missing, so it can be used in a build script.
Without the script: harness scan <Mod.dll> <game folder>, harness dump <game folder> <Type::Method>, harness diff <old game folder> <new game folder> <Type::Method>.
Build
dotnet build plugin -c Release -o bin # YummiHarness.dll
dotnet build cli -c Release -o bin # harness.exe
Limitations
- The fingerprint covers only the target method itself, not the methods it calls.
- At runtime the game's IL is read through the Mono.Cecil that ships with BepInEx.