Getting Started
Install
Add the package to your mod project:
<PackageReference Include="STS2.RitsuLib" />Declare the runtime dependency in mod_manifest.json. For game API 0.105.x and newer, use the object form:
{
"dependencies": [
{ "id": "STS2-RitsuLib" }
]
}For older game API branches, use the legacy string form because older manifest parsers may fail on dependency objects:
{
"dependencies": [
"STS2-RitsuLib"
]
}If you do not use Central Package Management, choose the current package version through your package manager or IDE. Use STS2.RitsuLib.Compat.<api-version> only when the mod targets an older Slay the Spire 2 API branch.
安装
在 Mod 项目里引用包:
<PackageReference Include="STS2.RitsuLib" />在 mod_manifest.json 声明运行时依赖。游戏 API 0.105.x 及之后使用对象写法:
{
"dependencies": [
{ "id": "STS2-RitsuLib" }
]
}旧游戏 API 分支使用旧的字符串写法;旧版 manifest 解析器可能无法解析 dependency 对象,甚至直接报错:
{
"dependencies": [
"STS2-RitsuLib"
]
}如果项目没有使用 Central Package Management,请通过包管理器或 IDE 选择当前包版本。只有在 Mod 面向旧版《杀戮尖塔 2》API 分支时,才使用 STS2.RitsuLib.Compat.<api-version>。
Initialize
Register your assembly for RitsuLib discovery from the mod initializer. This is required for CLR attribute registration.
using System.Reflection;
using MegaCrit.Sts2.Core.Logging;
using MegaCrit.Sts2.Core.Modding;
using STS2RitsuLib;
using STS2RitsuLib.Interop;
using STS2RitsuLib.Patching.Core;
[ModInitializer(nameof(Initialize))]
public static class MyModEntry
{
public const string ModId = "MyMod";
public static Logger Logger { get; private set; } = null!;
public static void Initialize()
{
var assembly = Assembly.GetExecutingAssembly();
Logger = RitsuLibFramework.CreateLogger(ModId);
ModTypeDiscoveryHub.RegisterModAssembly(ModId, assembly);
RitsuLibFramework.EnsureGodotScriptsRegistered(assembly, Logger);
var patcher = RitsuLibFramework.CreatePatcher(ModId, "main");
patcher.RegisterPatches<MyModPatches>();
RitsuLibFramework.ApplyRequiredPatcher(patcher, DisableMod);
}
private static void DisableMod()
{
// Mark your own mod disabled when a required patch cannot apply.
}
}Call EnsureGodotScriptsRegistered(...) only when your mod contains C# scripts attached to .tscn scenes. Pure model or patch mods can omit it.
初始化
在 Mod 初始化入口注册当前程序集,RitsuLib 才能发现 CLR 注解注册。
using System.Reflection;
using MegaCrit.Sts2.Core.Logging;
using MegaCrit.Sts2.Core.Modding;
using STS2RitsuLib;
using STS2RitsuLib.Interop;
using STS2RitsuLib.Patching.Core;
[ModInitializer(nameof(Initialize))]
public static class MyModEntry
{
public const string ModId = "MyMod";
public static Logger Logger { get; private set; } = null!;
public static void Initialize()
{
var assembly = Assembly.GetExecutingAssembly();
Logger = RitsuLibFramework.CreateLogger(ModId);
ModTypeDiscoveryHub.RegisterModAssembly(ModId, assembly);
RitsuLibFramework.EnsureGodotScriptsRegistered(assembly, Logger);
var patcher = RitsuLibFramework.CreatePatcher(ModId, "main");
patcher.RegisterPatches<MyModPatches>();
RitsuLibFramework.ApplyRequiredPatcher(patcher, DisableMod);
}
private static void DisableMod()
{
// 必要补丁无法应用时,在这里关闭你自己的 Mod。
}
}只有 Mod 里有挂在 .tscn 场景上的 C# 脚本时,才需要 EnsureGodotScriptsRegistered(...)。纯模型或纯补丁 Mod 可以省略。
Register Content
For most content, put registration attributes on the model class. The registration point stays next to the class that is being registered.
using Godot;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Models;
using STS2RitsuLib.Interop.AutoRegistration;
using STS2RitsuLib.Scaffolding.Content;
public sealed class MyCardPool : TypeListCardPoolModel
{
public override string Title => "My Cards";
public override string EnergyColorName => "orange";
public override string CardFrameMaterialPath => "card_frame_orange";
public override Color DeckEntryCardColor => new("d58b2f");
public override bool IsColorless => false;
}
[RegisterCard(typeof(MyCardPool))]
public sealed class MyStrike
: ModCardTemplate(1, CardType.Attack, CardRarity.Common, TargetType.SingleEnemy)
{
public override void Use(ICombatContext ctx, ICreatureState user, ICreatureState? target)
{
ctx.DealDamage(user, target, Damage);
}
}Write the display text in the matching localization table:
{
"MY_MOD_CARD_MY_STRIKE.title": "Measured Strike",
"MY_MOD_CARD_MY_STRIKE.description": "Deal {Damage} damage."
}Use a content pack instead when the registration is easier to read as a batch:
RitsuLibFramework.CreateContentPack("MyMod")
.Card<MyCardPool, MyStrike>()
.Relic<MyRelicPool, MyStarterRelic>()
.Apply();注册内容
大多数内容可以把注册注解写在模型类上。注册点会贴近真正的内容定义,更容易维护。
using Godot;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Models;
using STS2RitsuLib.Interop.AutoRegistration;
using STS2RitsuLib.Scaffolding.Content;
public sealed class MyCardPool : TypeListCardPoolModel
{
public override string Title => "My Cards";
public override string EnergyColorName => "orange";
public override string CardFrameMaterialPath => "card_frame_orange";
public override Color DeckEntryCardColor => new("d58b2f");
public override bool IsColorless => false;
}
[RegisterCard(typeof(MyCardPool))]
public sealed class MyStrike
: ModCardTemplate(1, CardType.Attack, CardRarity.Common, TargetType.SingleEnemy)
{
public override void Use(ICombatContext ctx, ICreatureState user, ICreatureState? target)
{
ctx.DealDamage(user, target, Damage);
}
}显示文本写在对应本地化表里:
{
"MY_MOD_CARD_MY_STRIKE.title": "精准打击",
"MY_MOD_CARD_MY_STRIKE.description": "造成 {Damage} 点伤害。"
}如果一批注册集中写更容易审查,也可以使用 content pack:
RitsuLibFramework.CreateContentPack("MyMod")
.Card<MyCardPool, MyStrike>()
.Relic<MyRelicPool, MyStarterRelic>()
.Apply();Next Steps
- Registration APIs: Content authoring
- Localization keys: Localization and keywords
- Characters: Character and unlock scaffolding
- Saves: Persistence
- Settings: Mod settings