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()
签名:
String id();行为:返回皮肤 id(建议写成 "mymod:neon" 形态)。身份以注册键为准:注册键的 namespace:path 才是玩家侧皮肤 id,宿主加载皮肤时不读取本方法;它只用于模组自述与日志。
示例:
@Override
public String id() {
return "mymod:neon";
}displayName()
签名:
String displayName();行为:返回显示名,用于视觉资源包列表的 NAME 列。列表扫描期间若本方法抛异常,该皮肤会被跳过(限频告警);构建皮肤时抛异常则回退为皮肤 id 字符串。
示例:
@Override
public String displayName() {
return "Neon (mod)";
}image(SkinSlot slot)
签名:
String image(SkinSlot slot);行为:返回该槽位的资源标识字符串("<namespace>:<path>" 形态,即 ResourceLocation 的字符串形式),不是已加载图像。宿主用既有资源管线两级查找并解码:磁盘覆盖 data/mods/<模组id>/assets/<namespace>/<path> → 模组 jar 内 assets/<namespace>/<path>。返回 null 或空白表示该槽位无素材(留空、渲染回退默认)。标识非法、查找未命中或解码失败时,宿主限频告警(10 秒)并只留空该槽位,不影响其余槽位、不崩溃。
示例:
@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()
签名:
default String noteJson();行为:返回与 respack note.json 同语义的 JSON 文本(name / normal / hold / exploit / payload / custom 段),宿主用同一解析器构建字符皮肤;返回 null(默认)表示图片皮肤,四槽位各取 image(slot) 的 PNG。JSON 解析失败时该皮肤被标记加载错误,setCurrentSkin 会拒绝切换并保持当前皮肤。列表扫描期间若本方法抛异常,该皮肤会被跳过(限频告警)。
示例:
@Override
public String noteJson() {
return """
{"name":"Neon","normal":{"prefix":"[","fill":"=","core":"O","suffix":"]"}}
""";
}完整签名
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 重试,模组可后启用)。
关键契约:
- 皮肤 id(注册键)必须是
<namespace>:<path>形态;命名空间为seecmd的 id 不会走模组皮肤通道,而会按 respack 文件夹名处理(通常找不到),因此模组应始终使用自己的模组 id 作命名空间。 data/respack/的扫描、加载与回退行为不受本注册表影响;注册表为空时皮肤列表与既有行为完全一致。- 线程:注册在
onPreInit(宿主线程);image()/noteJson()/displayName()在宿主加载皮肤时调用(进入游玩或预览时),实现应保持无状态或线程安全。
生命周期阶段:注册仅在 onPreInit;素材读取发生在游玩场景加载 / 视觉资源包预览时。
稳定性:2.0 加性新增(皮肤入管道);新增方法只增不破。