Content Packs And Registries
Builder Surface
CreateContentPack(modId) returns a chainable builder. Call Apply() once after adding every step.
| Category | Builder methods |
|---|---|
| Core models | .Card<TPool,TCard>(), .Relic<TPool,TRelic>(), .Potion<TPool,TPotion>(), .Power<TPower>(), .Orb<TOrb>() |
| Characters | .Character<TCharacter>(), .Character<TCharacter>(entry => ...), starter card / relic / potion helpers |
| World content | .Act<TAct>(), .Monster<TMonster>(), .ActEncounter<TAct,TEncounter>(), .GlobalEncounter<TEncounter>(), .SharedEvent<TEvent>(), .ActEvent<TAct,TEvent>(), .SharedAncient<TAncient>(), .ActAncient<TAct,TAncient>() |
| Metadata | .Achievement<T>(), .Enchantment<T>(), .Affliction<T>(), .Badge<T>(), .Singleton<T>(), modifiers |
| Text and ids | .CardKeywordOwnedByLocNamespace(...), .KeywordOwned(...), .CardTagOwned(...) |
| UI and piles | .CardPileOwned(...), .TopBarButtonOwned(...) |
| Timeline | .Story<T>(), .Epoch<T>(), .StoryEpoch<TStory,TEpoch>(), timeline slot helpers |
| Unlocks | .RequireEpoch<TModel,TEpoch>(), .UnlockEpochAfterWinAs<TCharacter,TEpoch>(), and related count / boss / elite helpers |
| Batch input | .ContentManifest(...), .KeywordManifest(...), .PackManifest(...), .Manifest(...) |
| Escape hatch | .Custom(ctx => ...) |
The builder applies steps in the order you added them. Keep model registration before unlock rules that reference those models.
Attribute Surface
Use attributes when the registration belongs next to the model type. Register the assembly first with ModTypeDiscoveryHub.RegisterModAssembly(modId, assembly).
| Category | Attributes |
|---|---|
| Pool content | RegisterCard, RegisterRelic, RegisterPotion |
| Standalone models | RegisterCharacter, RegisterPower, RegisterOrb, RegisterAchievement, RegisterSingleton |
| World content | RegisterAct, RegisterMonster, RegisterGlobalEncounter, RegisterActEncounter |
| Events | RegisterSharedEvent, RegisterActEvent, RegisterSharedAncient, RegisterActAncient, RegisterTrashHeapCard, RegisterTrashHeapRelic |
| Pools | RegisterSharedCardPool, RegisterSharedRelicPool, RegisterSharedPotionPool |
| Keywords and ids | RegisterOwnedKeyword, RegisterOwnedCardKeyword, RegisterOwnedCardTag |
| Timeline | RegisterStory, RegisterEpoch, RegisterStoryEpoch, AutoTimelineSlot* |
| Unlocks | RequireEpoch, RequireAllCardsInPool, RegisterEpochCards, RegisterEpochRelicsFromPool, UnlockEpochAfter* |
| UI | RegisterOwnedCardPile, RegisterOwnedTopBarButton |
| Special mappings | RegisterArchaicToothTranscendence, RegisterTouchOfOrobasRefinement |
Attributes also support Order, and pool-backed model attributes support StableEntryStem / FullPublicEntry. RegisterCharacterStarterCard, RegisterCharacterStarterRelic, and RegisterCharacterStarterPotion use Order for the final starter list order as well as operation ordering.
When an attribute is placed on an abstract base class, it is inherited only if Inherit = true is set. Inheritance is resolved by logical registration slot, with the nearest declaration winning. For example, a direct RegisterCard on a concrete card replaces an inherited RegisterCard even when it names a different pool; the card is not added to both pools. Configuration-only changes likewise replace inherited starter counts, node-attachment paths, timeline placement, and unlock thresholds. Registrations with distinct target ids or scopes remain additive, such as RequireEpoch entries for different epochs. Declaring the same logical slot more than once on one class is an error.
注解能力
当注册关系属于模型类型本身时,使用注解。先通过 ModTypeDiscoveryHub.RegisterModAssembly(modId, assembly) 注册程序集。
| 分类 | 注解 |
|---|---|
| 池内容 | RegisterCard、RegisterRelic、RegisterPotion |
| 独立模型 | RegisterCharacter、RegisterPower、RegisterOrb、RegisterAchievement、RegisterSingleton |
| 世界内容 | RegisterAct、RegisterMonster、RegisterGlobalEncounter、RegisterActEncounter |
| 事件 | RegisterSharedEvent、RegisterActEvent、RegisterSharedAncient、RegisterActAncient、RegisterTrashHeapCard、RegisterTrashHeapRelic |
| 池 | RegisterSharedCardPool、RegisterSharedRelicPool、RegisterSharedPotionPool |
| 关键词与 ID | RegisterOwnedKeyword、RegisterOwnedCardKeyword、RegisterOwnedCardTag |
| 时间线 | RegisterStory、RegisterEpoch、RegisterStoryEpoch、AutoTimelineSlot* |
| 解锁 | RequireEpoch、RequireAllCardsInPool、RegisterEpochCards、RegisterEpochRelicsFromPool、UnlockEpochAfter* |
| UI | RegisterOwnedCardPile、RegisterOwnedTopBarButton |
| 特殊映射 | RegisterArchaicToothTranscendence、RegisterTouchOfOrobasRefinement |
注解也支持 Order;带池的模型注解支持 StableEntryStem / FullPublicEntry。 RegisterCharacterStarterCard、RegisterCharacterStarterRelic、RegisterCharacterStarterPotion 的 Order 既用于操作排序,也用于最终 starter 列表排序。
注解放在抽象基类上时,只有设置 Inherit = true 才会传给派生类。继承按逻辑注册槽位解析,每个槽位采用最近的声明。例如,具体卡牌直接声明的 RegisterCard 会替换继承的 RegisterCard,即使二者指定不同卡池,也不会把卡同时加入两个池。只修改 starter 数量、节点挂载场景路径、时间线位置或解锁阈值时, 同样会替换继承配置。不同目标 ID 或作用域的注册仍会累加,例如针对不同纪元的多个 RequireEpoch。同一个类重复声明同一逻辑槽位会报错。
Builder 能力
CreateContentPack(modId) 返回链式 builder。把所有步骤加完后调用一次 Apply()。
| 分类 | Builder 方法 |
|---|---|
| 核心模型 | .Card<TPool,TCard>()、.Relic<TPool,TRelic>()、.Potion<TPool,TPotion>()、.Power<TPower>()、.Orb<TOrb>() |
| 角色 | .Character<TCharacter>()、.Character<TCharacter>(entry => ...)、初始卡牌 / 遗物 / 药水辅助方法 |
| 世界内容 | .Act<TAct>()、.Monster<TMonster>()、.ActEncounter<TAct,TEncounter>()、.GlobalEncounter<TEncounter>()、.SharedEvent<TEvent>()、.ActEvent<TAct,TEvent>()、.SharedAncient<TAncient>()、.ActAncient<TAct,TAncient>() |
| 元数据 | .Achievement<T>()、.Enchantment<T>()、.Affliction<T>()、.Badge<T>()、.Singleton<T>()、modifier 相关方法 |
| 文本和 ID | .CardKeywordOwnedByLocNamespace(...)、.KeywordOwned(...)、.CardTagOwned(...) |
| UI 与卡堆 | .CardPileOwned(...)、.TopBarButtonOwned(...) |
| 时间线 | .Story<T>()、.Epoch<T>()、.StoryEpoch<TStory,TEpoch>()、timeline slot 辅助方法 |
| 解锁 | .RequireEpoch<TModel,TEpoch>()、.UnlockEpochAfterWinAs<TCharacter,TEpoch>() 以及 run / boss / elite 计数辅助方法 |
| 批量输入 | .ContentManifest(...)、.KeywordManifest(...)、.PackManifest(...)、.Manifest(...) |
| 逃生口 | .Custom(ctx => ...) |
Builder 按添加顺序应用步骤。会引用模型的解锁规则应放在模型注册之后。
Direct Registries
Every builder method maps to a registry call. Direct registries are useful for shared helper libraries and conditional setup.
var content = RitsuLibFramework.GetContentRegistry("MyMod");
content.RegisterCard<MyCardPool, MyStrike>();
var keywords = RitsuLibFramework.GetKeywordRegistry("MyMod");
keywords.RegisterCardKeywordOwnedByLocNamespace("bleeding");| Registry | Access |
|---|---|
| Content | RitsuLibFramework.GetContentRegistry(modId) |
| Keywords | RitsuLibFramework.GetKeywordRegistry(modId) |
| Timeline | RitsuLibFramework.GetTimelineRegistry(modId) |
| Unlocks | RitsuLibFramework.GetUnlockRegistry(modId) |
| Card tags | RitsuLibFramework.GetCardTagRegistry(modId) |
| Card piles | RitsuLibFramework.GetCardPileRegistry(modId) |
| Top-bar buttons | RitsuLibFramework.GetTopBarButtonRegistry(modId) |
| SmartFormat | RitsuLibFramework.GetSmartFormatRegistry(modId) |
直接使用注册器
每个 builder 方法都对应一个注册器调用。共享辅助库或条件注册逻辑可以直接使用注册器。
var content = RitsuLibFramework.GetContentRegistry("MyMod");
content.RegisterCard<MyCardPool, MyStrike>();
var keywords = RitsuLibFramework.GetKeywordRegistry("MyMod");
keywords.RegisterCardKeywordOwnedByLocNamespace("bleeding");| 注册器 | 获取方式 |
|---|---|
| 内容 | RitsuLibFramework.GetContentRegistry(modId) |
| 关键词 | RitsuLibFramework.GetKeywordRegistry(modId) |
| 时间线 | RitsuLibFramework.GetTimelineRegistry(modId) |
| 解锁 | RitsuLibFramework.GetUnlockRegistry(modId) |
| 卡牌标签 | RitsuLibFramework.GetCardTagRegistry(modId) |
| 卡堆 | RitsuLibFramework.GetCardPileRegistry(modId) |
| 顶栏按钮 | RitsuLibFramework.GetTopBarButtonRegistry(modId) |
| SmartFormat | RitsuLibFramework.GetSmartFormatRegistry(modId) |
Manifests
Manifest arrays are useful when content is generated or split across files.
IContentRegistrationEntry[] content =
[
new CardRegistrationEntry<MyCardPool, MyStrike>(),
new RelicRegistrationEntry<MyRelicPool, MyRelic>(),
];
RitsuLibFramework.CreateContentPack("MyMod")
.ContentManifest(content)
.KeywordManifest(keywordEntries)
.PackManifest(timelineAndUnlockEntries)
.Apply();Use separate manifest methods when possible. It keeps ModelDb content, keyword ids, and timeline / unlock rules easy to review.
Manifest
当内容由工具生成,或拆在多个文件里时,可以使用 manifest 数组。
IContentRegistrationEntry[] content =
[
new CardRegistrationEntry<MyCardPool, MyStrike>(),
new RelicRegistrationEntry<MyRelicPool, MyRelic>(),
];
RitsuLibFramework.CreateContentPack("MyMod")
.ContentManifest(content)
.KeywordManifest(keywordEntries)
.PackManifest(timelineAndUnlockEntries)
.Apply();尽量使用拆开的 manifest 方法。这样 ModelDb 内容、关键词 ID、时间线 / 解锁规则更容易审查。
Registration Timing
Run content registration from your mod initializer. RitsuLib freezes content registration before the game finishes model initialization. After the freeze, adding models is invalid.
Subscribe to ContentRegistrationClosedEvent only for diagnostics. Do not wait for it to register content.
注册时机
内容注册应在 Mod 初始化入口执行。RitsuLib 会在游戏完成模型初始化前冻结内容注册。冻结后再添加模型属于无效操作。
ContentRegistrationClosedEvent 只适合诊断,不要等这个事件发生后再注册内容。