Skip to content

Add content source inspection#44

Merged
BAKAOLC merged 1 commit into
BAKAOLC:feat/what-mod-is-this-fromfrom
GlitchedReme:what-mod
May 21, 2026
Merged

Add content source inspection#44
BAKAOLC merged 1 commit into
BAKAOLC:feat/what-mod-is-this-fromfrom
GlitchedReme:what-mod

Conversation

@GlitchedReme
Copy link
Copy Markdown
Contributor

Summary / 概要

  • 在模组的HoverTip里添加一行该内容的mod来源
  • 将原来的hovertip改为只在卡牌和遗物的InspectScreen里添加
  • 提供一个IContentSourceSupplier以实现自定义模组来源显示(例如联动的模组卡牌)
图片 图片

Why / 背景与动机

  • 基础mod必备

What changed / 变更点

  • Content/ContentSourceHoverTipFactory.cs
  • Content/IContentSourceSupplier.cs
  • RitsuLibFramework.PatcherSetup.cs
  • Settings/Localization/ModSettingsUi/eng.json 以及 zhs.json

Notes / 备注

  • 自定义模组的WithTooltip未添加来源显示。
  • IContentSourceSupplier只提供了string类型并且已被颜色bbcode包裹。也许可以提供更好的接口。

@GlitchedReme
Copy link
Copy Markdown
Contributor Author

另外{DisplayName} ({Id})似乎有点冗余了,可以考虑两者相等时只展示一个

@ritsukage-local-analyzer
Copy link
Copy Markdown

Warning

此分析由 AI 自动生成,仅供开发者参考,最终判断请以人工确认为准。如有疑问建议结合本地环境进一步复现确认。

摘要

该 PR 为 RitsuLib 框架新增了内容来源悬停提示功能——在卡牌、遗物、药水等内容的悬停说明前追加一行标注「来自哪个 Mod」的紫色提示文字。代码规模适中(6 文件,+135/−56),架构清晰:工厂类负责来源解析与缓存,三个 Harmony patch 分别处理关键字、模型属性以及 InspectScreen 的悬停集合,提供 IContentSourceSupplier 接口供模组自定义来源字符串。可合并,建议关注反射字段依赖与卡牌 inspect screen 中 HoverTip 的双重注入风险。

重点结论

  • 变更简介: 在悬停提示(HoverTip)中自动注入「Mod 名称 (ModId)」格式的紫色行,覆盖关键字、多个模型类型(卡牌/遗物/药水/能力/诅咒/附魔/球体)以及在 NInspectCardScreen / NInspectRelicScreen 中展示;同时提供 IContentSourceSupplier 接口供模组自定义覆盖。
  • 主要风险: ContentSourceNHoverTipSetShowPatch 通过反射访问 NInspectCardScreen._cards / _index 等私有字段,游戏更新可能导致字段变更;卡牌的 HoverTip getter patch 与 inspect screen 的 CreateAndShow patch 可能对同一张卡产生双重注入。
  • 建议处理: 可合并(approve),条件为在合并前确认 inspect screen 中的双重悬停提示是否为预期行为,或由审核者判定是否需要去重。
  • 需要补充: 无——PR 正文说明了功能要点与已知限制(WithTooltip 暂不支持、IContentSourceSupplier API 可改进),信息充分。
展开详细审阅、证据与验证

变更概要

项目
源分支 what-modfeat/what-mod-is-this-from
Draft
文件数 6
新增行 +135
删除行 −56
Mergeable

行为变更范围: 用户可见——在游戏内的 HoverTip 悬停提示中添加 mod 来源信息行。内部实现了来源解析工厂、三个 Harmony 补丁、设置开关以及双语本地化。

PR 说明与代码对照

PR 正文列出 4 项变更点,全部在 diff 中体现:

  • Content/ContentSourceHoverTipFactory.cs — 新增,已覆盖
  • Content/IContentSourceSupplier.cs — 新增,已覆盖
  • RitsuLibFramework.PatcherSetup.cs — 修改(注册 3 个新 patch),已覆盖
  • Settings/Localization/ModSettingsUi/eng.json 与 zhs.json — 修改(新增 3 个键),已覆盖

PR 备注中提到的两个已知限制:

  • 自定义模组的 WithTooltip 未添加来源显示 — 已声明,需验证
  • IContentSourceSupplier 只提供 string 类型且已被颜色 bbcode 包裹 — 已声明,属于 API 设计讨论

详细代码审阅

ContentSourceHoverTipFactory.cs (新增)

  • TryCreate(AbstractModel, out IHoverTip): 入口方法,先检查设置开关,再解析来源并创建 HoverTip
  • Resolve(Type): 双重锁缓存查找 SourceByModelType,未命中则调用 ModContentRegistry.TryGetOwnerModId 或通过 assembly 遍历已加载 mod。
  • ResolveKeyword(CardKeyword): 通过 ModKeywordRegistry.TryGetByCardKeyword 查找自定义关键字所属 mod。
  • ContentSourceInfo.Format(): 输出 "{DisplayName} ({Id})",未添加任何 bbcode 颜色——实际颜色由 patch 层在 Append 中统一以 [purple] 包裹。

IContentSourceSupplier.cs (新增)

  • 接口仅包含一个 string ContentSource { get; } 属性,文档注释说明返回预格式化字符串。
  • ContentSourceHoverTipPatchHelper.Append(AbstractModel, ref IEnumerable<IHoverTip>)ContentSourceModelHoverTipPatch.Postfix 中通过 is IContentSourceSupplier 检查优先使用。

ContentSourceHoverTipPatches.cs (新增,3 个 patch)

Patch 类 目标方法 注入方式 作用范围
ContentSourceKeywordHoverTipPatch HoverTipFactory.FromKeyword Postfix 关键字的悬停提示
ContentSourceModelHoverTipPatch 6 个模型属性的 getter(Potion/HoverTip、Power/DumbHoverTip 等) Postfix 模型属性级别的悬停提示
ContentSourceNHoverTipSetShowPatch NHoverTipSet.CreateAndShow Prefix NInspectCardScreen / NInspectRelicScreen
  • 所有 patch 均标记 IsCritical = false,失败不影响核心功能。
  • 所有 patch 均有 IsModSourceHoverTipsEnabled() 守卫。
  • ContentSourceModelHoverTipPatchPotionModel、PowerModel、RelicModel、OrbModel、EnchantmentModel、AfflictionModel 的 HoverTip/DumbHoverTip getter 进行 postfix 注入。
  • ContentSourceNHoverTipSetShowPatch 通过反射访问 NInspectCardScreen._cards / _indexNInspectRelicScreen._relics / _index。这些字段名称需随游戏版本保持同步。当前通过 FieldInfo 缓存,字段不存在时静默跳过。

双重注入分析:

  • 对于卡牌:CardModel 未在 ContentSourceModelHoverTipPatch 的目标列表中(该 patch 仅覆盖 Potion/Power/Relic/Orb/Enchantment/Affliction 模型);卡牌的内容来源仅通过 ContentSourceNHoverTipSetShowPatch(inspect screen)注入。但关键字级别仍会通过 ContentSourceKeywordHoverTipPatch 在解析关键字时添加来源行——这是合理的分层。
  • 对于遗物:RelicModel.HoverTip getter 会被 ContentSourceModelHoverTipPatch 注入一次,同时 inspect screen 的 CreateAndShow 也会通过 ContentSourceNHoverTipSetShowPatch 注入。如果 inspect screen 内部的 HoverTip 集合也通过 RelicModel.HoverTip getter 获取基础悬停提示,则可能出现双重「来自哪个 Mod」行。

RitsuLibFramework.PatcherSetup.cs (修改)

  • RegisterContentAssetPatches() 中新增 3 行注册:
    patcher.RegisterPatch<ContentSourceKeywordHoverTipPatch>();
    patcher.RegisterPatch<ContentSourceModelHoverTipPatch>();
    patcher.RegisterPatch<ContentSourceNHoverTipSetShowPatch>();
    
  • 注册位置在 ContentAssets 区域,与其它内容资产补丁并列——位置恰当。

本地化 (修改)

  • eng.json 新增 3 个键:ritsulib.modSourceHoverTips.enabled.label.descriptionritsulib.modSourceHoverTip.title
  • zhs.json 对应中文翻译:"显示内容来源悬停提示""为卡牌、遗物和药水追加悬停提示,显示提供该内容的模组。""来自哪个Mod?"
  • 翻译准确、键名一致。

提交与范围规范性

标题「Add content source inspection」与变更内容匹配。6 个文件的变更范围聚焦于同一功能点,无明显无关改动或范围膨胀。变更量(+135/−56)与新增完整功能相符,无异常大块变更。无需拆分。

详细验证建议

  • 构建项目,确认 ContentSourceHoverTipPatches.cs、ContentSourceHoverTipFactory.cs、IContentSourceSupplier.cs 均能编译通过
  • 在游戏中启用「显示内容来源悬停提示」设置,检查不同 mod 的卡牌、遗物、药水是否正确显示来源行(格式 "ModName (ModId)")
  • 在 NInspectCardScreen 中打开来自 mod 的卡牌详情,确认悬停提示顶部出现紫色来源行
  • 在 NInspectRelicScreen 中打开来自 mod 的遗物详情,确认悬停提示顶部出现紫色来源行,且无重复行
  • 在卡牌图鉴中查看含自定义关键字的卡牌悬停提示,确认关键字行后追加了来源信息
  • 禁用设置开关,确认所有来源信息不再出现
  • 实现 IContentSourceSupplier 的测试模型,验证自定义来源字符串可正常覆盖默认解析
  • 对原版(Vanilla)内容,确认为 Vanilla 时不添加来源行

合并与回滚风险

  • 无数据迁移需求,回滚仅需移除 patch 注册并删除新增文件即可恢复
  • 设置开关默认为 true,合并后所有用户默认启用——如担心上线稳定性,可考虑临时将默认值改为 false 或在合并前充分测试
  • 反射字段名依赖(_cards_index_relics)是主要断裂点——游戏版本更新可能需要同步修改

English translation

Summary

This PR adds a content source hover tip feature to the RitsuLib framework — injecting a purple "which mod is this from?" line before existing hover tip descriptions for cards, relics, potions, and more. The change is well-scoped (6 files, +135/−56), with a clean architecture: a factory class handles source resolution and caching, three Harmony patches cover keywords, model property getters, and InspectScreen hover tip collections respectively, and an IContentSourceSupplier interface allows mods to supply custom source strings. Ready to merge, with a note to verify potential double-injection in the inspect screen flow.

Key Takeaways

  • What changed: Automatically injects a purple "ModName (ModId)" line into hover tips, covering keywords and multiple model types (card/relic/potion/power/curse/enchantment/orb), and visible in NInspectCardScreen / NInspectRelicScreen. An IContentSourceSupplier interface is provided for custom overrides.
  • Primary risk: ContentSourceNHoverTipSetShowPatch uses reflection on private fields (_cards, _index, _relics) which may break on game updates; dual injection is possible in relic inspect screens where both the model-level getter patch and the CreateAndShow prefix patch could append the source line.
  • Recommended action: Approve, conditional on verifying whether double hover tip injection in inspect screens is intended behavior, or upon reviewer confirmation that it's acceptable.
  • Needs more info: None — the PR body clearly states the feature scope and known limitations (no WithTooltip support yet, IContentSourceSupplier API could be improved).
Expand detailed analysis, evidence, and verification

Change Summary

Item Value
Source what-modfeat/what-mod-is-this-from
Draft No
Changed files 6
Additions +135
Deletions −56
Mergeable Yes

Behavioral scope: User-visible — adds a mod source info line to in-game hover tips. Internally implements a source resolution factory, three Harmony patches, settings toggle, and bilingual localization.

PR Description vs. Code

The PR body lists 4 change items, all accounted for in the diff:

  • Content/ContentSourceHoverTipFactory.cs — new, covered
  • Content/IContentSourceSupplier.cs — new, covered
  • RitsuLibFramework.PatcherSetup.cs — modified (registers 3 new patches), covered
  • Settings/Localization/ModSettingsUi/eng.json & zhs.json — modified (3 new keys added), covered

Known limitations stated in the PR:

  • Custom mod WithTooltip does not yet include source display — acknowledged, needs verification
  • IContentSourceSupplier only provides a string with bbcode wrapping — acknowledged, API design discussion

Detailed Code Review

ContentSourceHoverTipFactory.cs (new)

  • TryCreate(AbstractModel, out IHoverTip): Entry point — checks settings toggle, resolves source, then creates a HoverTip.
  • Resolve(Type): Double-lock cached lookup via SourceByModelType; on miss, queries ModContentRegistry.TryGetOwnerModId or iterates loaded mods by assembly match.
  • ResolveKeyword(CardKeyword): Delegates to ModKeywordRegistry.TryGetByCardKeyword for custom keyword source resolution.
  • ContentSourceInfo.Format(): Returns "{DisplayName} ({Id})" — no bbcode. The purple color wrapping is applied uniformly in the patch layer via Append.

IContentSourceSupplier.cs (new)

  • Single property string ContentSource { get; } — documentation states the string is pre-formatted.
  • Priority path: checked via is IContentSourceSupplier in both ContentSourceHoverTipPatchHelper.Append and ContentSourceModelHoverTipPatch.Postfix.

ContentSourceHoverTipPatches.cs (new, 3 patches)

Patch Class Target Method Hook Scope
ContentSourceKeywordHoverTipPatch HoverTipFactory.FromKeyword Postfix Keyword hover tips
ContentSourceModelHoverTipPatch 6 model property getters (Potion.HoverTip, Power.DumbHoverTip, etc.) Postfix Model property-level hover tips
ContentSourceNHoverTipSetShowPatch NHoverTipSet.CreateAndShow Prefix NInspectCardScreen / NInspectRelicScreen
  • All patches: IsCritical = false (non-blocking), guarded by IsModSourceHoverTipsEnabled().
  • ContentSourceModelHoverTipPatch targets property getters for PotionModel, PowerModel, RelicModel, OrbModel, EnchantmentModel, AfflictionModel.
  • ContentSourceNHoverTipSetShowPatch accesses private fields via cached FieldInfo — silently skips if fields are absent. Field names (_cards, _index, _relics) must stay in sync with game updates.

Dual injection analysis:

  • For cards: CardModel is not in the ContentSourceModelHoverTipPatch target list; card content source only appears via ContentSourceNHoverTipSetShowPatch (inspect screen). Keywords additionally receive source lines through ContentSourceKeywordHoverTipPatch — this is appropriate layering.
  • For relics: RelicModel.HoverTip getter is patched by ContentSourceModelHoverTipPatch, and inspect screen CreateAndShow adds another via ContentSourceNHoverTipSetShowPatch. If the inspect screen internally calls RelicModel.HoverTip to populate the tip set, dual "what mod is this from?" lines may appear.

RitsuLibFramework.PatcherSetup.cs (modified)

  • Three new patch registrations in RegisterContentAssetPatches():
    patcher.RegisterPatch<ContentSourceKeywordHoverTipPatch>();
    patcher.RegisterPatch<ContentSourceModelHoverTipPatch>();
    patcher.RegisterPatch<ContentSourceNHoverTipSetShowPatch>();
    
  • Located in the ContentAssets area alongside other content asset patches — appropriate placement.

Localization (modified)

  • eng.json: 3 new keys — ritsulib.modSourceHoverTips.enabled.label, .description, ritsulib.modSourceHoverTip.title
  • zhs.json: Correct Chinese translations — "显示内容来源悬停提示", "为卡牌、遗物和药水追加悬停提示,显示提供该内容的模组。", "来自哪个Mod?"
  • Keys are consistent and translations are accurate.

Commit & Scope Compliance

Title "Add content source inspection" matches the change scope. All 6 files are tightly focused on a single feature, with no unrelated changes or scope creep. The change volume (+135/−56) is proportionate to adding a complete new feature. No splitting needed.

Verification Checklist

  • Build the project — confirm all new files compile successfully
  • Enable "Show content source hover tips" in settings, verify correct source line format ("ModName (ModId)") for cards, relics, and potions from various mods
  • Open a mod-card in NInspectCardScreen — confirm a purple source line appears at the top of the hover tip
  • Open a mod-relic in NInspectRelicScreen — confirm a purple source line appears at the top, with no duplicate lines
  • Hover over a card with custom keywords in the compendium — confirm source info is appended after keyword details
  • Disable the settings toggle — confirm all source info disappears
  • Implement a test model with IContentSourceSupplier — verify custom source string overrides default resolution
  • Verify vanilla content does not receive a source line

Merge & Rollback Risk

  • No data migration required; rollback only requires removing patch registrations and the 3 new files
  • Settings toggle defaults to true — all users will have the feature enabled on merge. If stability is a concern, consider temporarily defaulting to false or testing thoroughly before merge
  • Reflection field name dependency (_cards, _index, _relics) is the primary breakpoint — game version updates may require synchronized field name changes

工具侧记录
  • BAKAOLC/STS2-RitsuLib#44 · 退出码 0 · 进程 329.68s
  • deepseek-v4-pro · API 328476ms · 29 轮 · ↓67666 ↑9197 · 缓存读618624 写0 · $0.8776
  • MCP available: management tools exposed to Claude.

@BAKAOLC BAKAOLC merged commit d36294e into BAKAOLC:feat/what-mod-is-this-from May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants