Theseus 模组文档
API 参考 / spi 包:游戏模式、谱面扩展与内容

SkinProvider


把一套音符皮肤接入宿主皮肤系统(data/respack/ 皮肤的模组等价物)。在注册窗口内经 ctx.registries().skins() 注册,注册键即玩家侧皮肤 id(如 RegistryKey.of("mymod", "neon", SkinProvider.class) → 皮肤 id mymod:neon)。注册后皮肤出现在视觉资源包场景(/mnt/respack/)列表末尾,选中即应用并随 settings.json 的 skin 键持久化——与 respack 皮肤同一条管道。相关类型:SkinSlot。

方法速览

方法用途
id()自述用皮肤 id(宿主解析不依赖)
displayName()视觉资源包列表中的显示名
image(SkinSlot)槽位素材的资源标识字符串
noteJson()字符皮肤 JSON(null = 图片皮肤)

id()

签名:

java
String id();

行为:返回皮肤 id(建议写成 "mymod:neon" 形态)。身份以注册键为准:注册键的 namespace:path 才是玩家侧皮肤 id,宿主加载皮肤时不读取本方法;它只用于模组自述与日志。

示例:

java
@Override
public String id() {
    return "mymod:neon";
}

displayName()

签名:

java
String displayName();

行为:返回显示名,用于视觉资源包列表的 NAME 列。列表扫描期间若本方法抛异常,该皮肤会被跳过(限频告警);构建皮肤时抛异常则回退为皮肤 id 字符串。

示例:

java
@Override
public String displayName() {
    return "Neon (mod)";
}

image(SkinSlot slot)

签名:

java
String image(SkinSlot slot);

行为:返回该槽位的资源标识字符串("<namespace>:<path>" 形态,即 ResourceLocation 的字符串形式),不是已加载图像。宿主用既有资源管线两级查找并解码:磁盘覆盖 data/mods/<模组id>/assets/<namespace>/<path> → 模组 jar 内 assets/<namespace>/<path>。返回 null 或空白表示该槽位无素材(留空、渲染回退默认)。标识非法、查找未命中或解码失败时,宿主限频告警(10 秒)并只留空该槽位,不影响其余槽位、不崩溃。

示例:

java
@Override
public String image(SkinSlot slot) {
    return switch (slot) {
        case NORMAL -> "mymod:skin/normal.png";
        case HOLD -> "mymod:skin/hold.png";
        case EXPLOIT -> "mymod:skin/exploit.png";
        case PAYLOAD -> "mymod:skin/payload.png";
    };
}

noteJson()

签名:

java
default String noteJson();

行为:返回与 respack note.json 同语义的 JSON 文本(name / normal / hold / exploit / payload / custom 段),宿主用同一解析器构建字符皮肤;返回 null(默认)表示图片皮肤,四槽位各取 image(slot) 的 PNG。JSON 解析失败时该皮肤被标记加载错误,setCurrentSkin 会拒绝切换并保持当前皮肤。列表扫描期间若本方法抛异常,该皮肤会被跳过(限频告警)。

示例:

java
@Override
public String noteJson() {
    return """
            {"name":"Neon","normal":{"prefix":"[","fill":"=","core":"O","suffix":"]"}}
            """;
}

完整签名

java
public interface SkinProvider {

    String id();

    String displayName();

    String image(SkinSlot slot);

    default String noteJson();
}

素材放置:模组应把图片放在 src/main/resources/assets/<模组id>/skin/normal.png 等处,四槽位分别为 normal.png / hold.png / exploit.png / payload.png。建议尺寸与 respack 规范一致:normal / exploit / payload 为 1000×100,hold 为 1000×1100;不达标仍可加载(标记非规范)。

容错语义:任一槽位解析失败(标识非法 / 两级查找未命中 / 无法解码)或 displayName() / noteJson() / image() 抛异常,宿主限频告警(同一问题 10 秒内不重复),该槽位留空、渲染回退默认,不崩溃、不影响其余槽位;id 未注册或构建失败时 setCurrentSkin 告警并保持当前皮肤不变(下次进入游玩会按持久化皮肤 id 重试,模组可后启用)。

关键契约:

生命周期阶段:注册仅在 onPreInit;素材读取发生在游玩场景加载 / 视觉资源包预览时。

稳定性:2.0 加性新增(皮肤入管道);新增方法只增不破。