跳转到内容

Spartan Shields API 参考

本文档提供了 Spartan Shields Unofficial 模组的完整 API 开发指南。开发者可以使用此 API 创建自定义盾牌、注册新的资源类型、以及自定义塔盾渲染。

💡 Mod ID: spartan_shields_unofficial(带下划线)

💡 Java 包名: org.xiyu.spartanshieldsunofficial(无下划线)

💡 API 包: org.xiyu.spartanshieldsunofficial.api

api/
├── SpartanShieldsAPI.java // 唯一入口
├── shield/
│ ├── IShieldMaterial.java // 盾牌材质
│ ├── ShieldType.java // BASIC / TOWER 枚举
│ ├── ShieldBuilder.java // 流式建造者
│ └── IShieldBlockHandler.java // 格挡回调
├── resource/
│ ├── IResourceType.java // 资源类型定义
│ ├── IResourceStorage.java // 资源存储操作
│ ├── ResourceRegistry.java // 资源类型注册表
│ ├── SimpleResourceType.java // 通用实现基类
│ └── AbstractEnergyStorage.java // FE 存储封装
├── tag/
│ └── ShieldTags.java // TagKey 常量
└── client/
└── ITowerShieldRenderer.java // 塔盾渲染接口

如需了解如何使用 Spartan Shields API 的完整工作示例,请参阅官方示例附属模组:

Spartan Shields Unofficial 示例附属模组

该仓库演示了:

  • 使用自定义材质创建盾牌
  • 注册自定义资源类型
  • 实现格挡处理器和效果
  • 自定义塔盾渲染
  • 正确的模组结构和配置

build.gradle 中添加 Spartan Shields Unofficial 作为依赖项:

repositories {
maven {
url "https://cursemaven.com"
content {
includeGroup "curse.maven"
}
}
}
dependencies {
// 替换 xxxxx 和 yyyyy 为 CurseForge 上的 Project ID 和 File ID
implementation "curse.maven:spartan-shields-unofficial-xxxxx:yyyyy"
}

所有 API 操作都从 SpartanShieldsAPI 出发:

import org.xiyu.spartanshieldsunofficial.api.SpartanShieldsAPI;
方法说明
createMaterial(int, int, TagKey<Item>)创建盾牌材质
createMaterial(Tier, TagKey<Item>)从原版 Tier 创建盾牌材质
registerResourceType(IResourceType)注册新的资源类型
getResourceType(ResourceLocation)查询已注册的资源类型
getAllResourceTypes()获取所有已注册的资源类型
registerTowerShieldRenderer(Item, ITowerShieldRenderer)注册塔盾自定义渲染器(仅客户端)

import org.xiyu.spartanshieldsunofficial.api.SpartanShieldsAPI;
import org.xiyu.spartanshieldsunofficial.api.shield.IShieldMaterial;
// 方式一:直接指定数值
IShieldMaterial mithril = SpartanShieldsAPI.createMaterial(
800, // 基础耐久值
18, // 附魔能力值
MyTags.MITHRIL_INGOT // 修复材料 Tag
);
// 方式二:从原版 Tier 创建
IShieldMaterial diamond = SpartanShieldsAPI.createMaterial(
Tiers.DIAMOND, // 使用钻石级属性
Tags.Items.GEMS_DIAMOND // 修复材料 Tag
);
方法返回类型说明
getDurability()int基础耐久值(塔盾自动 ×1.25 倍率)
getEnchantability()int附魔能力值
getRepairTag()TagKey<Item>铁砧修复材料 Tag

ShieldBuilder 是创建盾牌的核心工具,支持流式 API:

import org.xiyu.spartanshieldsunofficial.api.shield.ShieldBuilder;
import org.xiyu.spartanshieldsunofficial.api.shield.ShieldType;
// 注册一个基础盾牌
DeferredHolder<Item, ?> MITHRIL_SHIELD = ITEMS.register("mithril_shield",
ShieldBuilder.create()
.material(mithril)
.build()
);
// 注册一个塔盾
DeferredHolder<Item, ?> MITHRIL_TOWER = ITEMS.register("mithril_tower_shield",
ShieldBuilder.create()
.material(mithril)
.type(ShieldType.TOWER)
.build()
);
方法说明必需/可选
create()创建新的 Builder 实例
material(IShieldMaterial)设置材质(耐久型盾牌)poweredBy 二选一
type(ShieldType)设置盾牌类型,默认 BASIC可选
blockEffect(Holder<MobEffect>, int, int)格挡时施加状态效果(可叠加)可选
blockHandler(IShieldBlockHandler)格挡时执行自定义逻辑(可叠加)可选
poweredBy(IResourceType, int, int)使盾牌由资源供能material 二选一
bashable(boolean)是否启用盾牌猛击,默认 true可选
build()构建为 Supplier<? extends ShieldBaseItem>必需
说明
BASIC基础盾牌
TOWER塔盾 — 更大防护面积,耐久/容量 ×1.25,BEWLR 3D 渲染

blockEffectblockHandler 支持多次调用,效果依序叠加:

DeferredHolder<Item, ?> CURSED_SHIELD = ITEMS.register("cursed_shield",
ShieldBuilder.create()
.material(mithril)
.blockEffect(MobEffects.WITHER, 60, 1) // 凋零 II, 3秒
.blockEffect(MobEffects.MOVEMENT_SLOWDOWN, 100, 2) // 缓慢 III, 5秒
.blockHandler((shield, player, attacker, dmg) -> {
// 播放自定义音效
player.level().playSound(null, player.blockPosition(),
SoundEvents.WITHER_SPAWN, SoundSource.PLAYERS, 0.5f, 1.0f);
})
.build()
);
@FunctionalInterface
public interface IShieldBlockHandler {
/**
* 盾牌成功格挡攻击时调用(伤害 ≥ 3.0 触发)。
*
* @param shield 盾牌 ItemStack
* @param player 持盾玩家
* @param attacker 攻击者(始终为 LivingEntity)
* @param damage 原始伤害值
*/
void onBlock(ItemStack shield, Player player, LivingEntity attacker, float damage);
}

支持 Lambda 表达式,例如:

.blockHandler((shield, player, attacker, dmg) -> attacker.igniteForSeconds(3))

build() 方法内置 validate() 校验,不合法的配置会在模组启动阶段立即抛出 IllegalStateException

错误场景异常信息
既无 material 也无 poweredBy”Shield must have either a material or a resource type”
同时设置 materialpoweredBy”Shield cannot have both material AND resource type”
poweredBycapacity ≤ 0”poweredBy capacity must be > 0”
poweredBymaxReceive ≤ 0”poweredBy maxReceive must be > 0”
// ❌ 错误:空壳盾牌
ShieldBuilder.create().build();
// → IllegalStateException
// ❌ 错误:同时设置材质和资源
ShieldBuilder.create().material(mat).poweredBy(ResourceRegistry.ENERGY, 100000, 500).build();
// → IllegalStateException
// ✅ 正确
ShieldBuilder.create().material(mat).build();
ShieldBuilder.create().poweredBy(ResourceRegistry.ENERGY, 500000, 2000).build();

资源系统是 API 的核心扩展点,允许附属模组注册任意类型的能量/魔力/应力作为盾牌的供能来源。

每种资源类型都是一个 IResourceType 实例,定义了资源的存储、显示和 Capability 注册行为。

方法说明
getId()全局唯一 ID,如 neoforge:energy
getDisplayName()Tooltip 中的显示名,如 FE
getDataComponent()关联的 DataComponentType(1.21+ 同步关键)
getStored(ItemStack)读取当前存储量
setStored(ItemStack, int)写入存储量
formatCapacityTooltip(int, int)格式化容量显示
formatChargeRateTooltip(int)格式化充能速率显示
formatPerDamageTooltip(int)格式化每次伤害消耗显示
getBarColor()物品耐久条颜色 (RGB)
onRegisterCapabilities(...)注册 NeoForge Capability(可选,默认空实现)

ResourceRegistry 中预置了 2 种资源类型:

常量ID显示名耐久条颜色说明
ResourceRegistry.ENERGYneoforge:energyFE蓝色 0x69B3FFNeoForge 标准能量单位
ResourceRegistry.MICRO_INFINITYenderio:micro_infinityµI绿色 0x4DA24BEnderIO 能量单位(底层复用 FE)

使用预置资源类型创建能量盾牌

Section titled “使用预置资源类型创建能量盾牌”
import org.xiyu.spartanshieldsunofficial.api.resource.ResourceRegistry;
DeferredHolder<Item, ?> FLUX_SHIELD = ITEMS.register("flux_shield",
ShieldBuilder.create()
.type(ShieldType.TOWER)
.poweredBy(ResourceRegistry.ENERGY, 500000, 2000)
.build()
);
// ✅ 不需要手动注册 Capability!
// 主模组在 RegisterCapabilitiesEvent 时自动处理:
// 1. 扫描所有通过 ShieldBuilder.poweredBy() 创建的盾牌
// 2. 调用 resourceType.onRegisterCapabilities()
// 3. AbstractEnergyStorage 自动注册 Capabilities.EnergyStorage.ITEM

使用 SimpleResourceType(推荐,只需 4 个参数)

Section titled “使用 SimpleResourceType(推荐,只需 4 个参数)”

SimpleResourceType 提供了 IResourceType 的开箱即用实现,自动处理 getStored/setStored/format*Tooltip

import org.xiyu.spartanshieldsunofficial.api.resource.SimpleResourceType;
import org.xiyu.spartanshieldsunofficial.api.SpartanShieldsAPI;
// 第一步:注册自己的 DataComponent(必须包含 networkSynchronized!)
public class MyDataComponents {
public static final DeferredRegister.DataComponents COMPONENTS =
DeferredRegister.createDataComponents("my_addon_mod");
public static final DeferredHolder<DataComponentType<?>, DataComponentType<Integer>> STORED_MANA =
COMPONENTS.registerComponentType("stored_mana", builder ->
builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.INT)
);
}
// 第二步:在模组构造器中注册资源类型
// 注意:直接传入 DeferredHolder(它实现了 Supplier),不要调用 .get()!
// 模组构造器阶段注册表事件尚未触发,.get() 会抛出 NullPointerException
SpartanShieldsAPI.registerResourceType(new SimpleResourceType(
ResourceLocation.fromNamespaceAndPath("botania", "mana"), // 全局唯一 ID
Component.literal("Mana"), // 显示名
MyDataComponents.STORED_MANA, // DeferredHolder IS-A Supplier
0x00C6FF // 耐久条颜色
));
// 第三步:使用该资源类型创建盾牌
IResourceType mana = ResourceRegistry.get(
ResourceLocation.fromNamespaceAndPath("botania", "mana")
).orElseThrow();
DeferredHolder<Item, ?> MANA_SHIELD = ITEMS.register("mana_shield",
ShieldBuilder.create()
.poweredBy(mana, 10000, 100)
.blockEffect(MobEffects.REGENERATION, 40, 0) // 还能同时加回血效果
.build()
);

想自定义 Tooltip 格式?直接 override:

IResourceType customMana = new SimpleResourceType(...) {
@Override
public Component formatCapacityTooltip(int stored, int capacity) {
return Component.literal("" + stored + " / " + capacity + " Mana")
.withStyle(ChatFormatting.AQUA);
}
};

使用 AbstractEnergyStorage(FE 兼容型资源)

Section titled “使用 AbstractEnergyStorage(FE 兼容型资源)”

如果你的资源类型底层仍是 NeoForge Energy(如 RF),使用 AbstractEnergyStorage 可自动注册 Capabilities.EnergyStorage.ITEM

import org.xiyu.spartanshieldsunofficial.api.resource.AbstractEnergyStorage;
// 创建一个显示为 "RF" 的能量类型(底层仍是 FE)
SpartanShieldsAPI.registerResourceType(new AbstractEnergyStorage(
ResourceLocation.fromNamespaceAndPath("thermal", "redstone_flux"),
Component.literal("RF"),
ModDataComponents.STORED_ENERGY, // DeferredHolder IS-A Supplier,直接传入
0xCC4C4C // 红色耐久条
));
IResourceType (接口)
└── SimpleResourceType (通用基类,4 参数即用)
└── AbstractEnergyStorage (FE 适配,自动注册 Capability)
使用场景
IResourceType需要完全自定义的资源类型(如复杂的魔力系统)
SimpleResourceType大部分场景 — 只需 4 个参数,自带默认 Tooltip 格式
AbstractEnergyStorage基于 FE 的资源类型 — 自动注册 NeoForge Energy Capability

附属模组可通过 instanceof IResourceStorage 判断盾牌是否为资源供能类型,并进行读写操作:

if (shieldItem instanceof IResourceStorage storage) {
IResourceType type = storage.getResourceType();
int capacity = storage.getCapacity();
int maxReceive = storage.getMaxReceive();
// 接收资源
int received = storage.receive(stack, 1000, false);
// 提取资源(盾牌默认返回 0)
int extracted = storage.extract(stack, 1000, false);
}
方法返回类型说明
getResourceType()IResourceType获取该盾牌使用的资源类型
getCapacity()int获取最大容量
getMaxReceive()int获取最大接收速率
receive(ItemStack, int, boolean)int接收资源,返回实际接收量
extract(ItemStack, int, boolean)int提取资源,返回实际提取量

ResourceRegistry 对重复 ID 注册会立即抛出 IllegalArgumentException

// 第一次注册 — 成功
SpartanShieldsAPI.registerResourceType(myMana);
// 第二次注册同一 ID — 抛出异常
SpartanShieldsAPI.registerResourceType(anotherMana);
// → IllegalArgumentException: Resource type 'botania:mana' is already registered!
// 建议:先检查是否已存在
ResourceRegistry.get(ResourceLocation.fromNamespaceAndPath("botania", "mana"))
.ifPresentOrElse(
existing -> { /* 已被其他附属模组注册,直接使用 */ },
() -> { /* 尚未注册,执行注册 */ }
);

ShieldTags 提供了公开的 TagKey<Item> 常量。附属模组将自定义盾牌加入这些 Tag 即可获得对应功能:

常量Tag 路径功能
ShieldTags.BASIC_SHIELDSspartan_shields_unofficial:basic_shields基础盾牌附魔支持
ShieldTags.TOWER_SHIELDSspartan_shields_unofficial:tower_shields塔盾附魔支持
ShieldTags.SHIELDS_WITH_BASHspartan_shields_unofficial:shields_with_bash盾击功能

在数据包的 Tag JSON 文件中添加您的盾牌:

data/spartan_shields_unofficial/tags/item/basic_shields.json
{
"replace": false,
"values": [
"mymod:mithril_shield"
]
}

为自定义塔盾提供完整的渲染控制,合并了模型、纹理和着色为单一接口:

方法返回类型说明默认值
createLayerDefinition()LayerDefinition模型定义必须实现
createModel(ModelPart)ShieldBaseModel创建模型实例必须实现
getTextureNoPattern()ResourceLocation无旗帜图案纹理必须实现
getTexturePattern()ResourceLocation有旗帜图案纹理必须实现
hasExtraLayers()boolean是否有额外渲染层false
getExtraLayerRenderType(ItemStack)RenderType额外层 RenderTypeRenderType.solid()
tintRed()float着色红通道 (0.0~1.0)1.0f
tintGreen()float着色绿通道 (0.0~1.0)1.0f
tintBlue()float着色蓝通道 (0.0~1.0)1.0f

正确的注册方式:

// 在模组构造器中
public MyMod(IEventBus modBus, Dist dist) {
if (dist == Dist.CLIENT) {
modBus.addListener(this::onClientSetup);
}
}
private void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
SpartanShieldsAPI.registerTowerShieldRenderer(
MY_TOWER_SHIELD.get(),
new ITowerShieldRenderer() {
@Override
public LayerDefinition createLayerDefinition() { /* ... */ }
@Override
public ShieldBaseModel createModel(ModelPart root) { /* ... */ }
@Override
public ResourceLocation getTextureNoPattern() {
return ResourceLocation.fromNamespaceAndPath("mymod", "textures/entity/shield/my_tower.png");
}
@Override
public ResourceLocation getTexturePattern() {
return ResourceLocation.fromNamespaceAndPath("mymod", "textures/entity/shield/my_tower_pattern.png");
}
@Override
public float tintRed() { return 0.8f; } // 自定义着色
@Override
public float tintGreen() { return 0.9f; }
@Override
public float tintBlue() { return 1.0f; }
}
);
});
}

public class MyShieldAddon {
public static final DeferredRegister<Item> ITEMS =
DeferredRegister.create(Registries.ITEM, "my_addon");
static final IShieldMaterial MITHRIL =
SpartanShieldsAPI.createMaterial(800, 18, MyTags.MITHRIL_INGOT);
public static final DeferredHolder<Item, ?> MITHRIL_SHIELD =
ITEMS.register("mithril_shield",
ShieldBuilder.create().material(MITHRIL).build()
);
public static final DeferredHolder<Item, ?> MITHRIL_TOWER =
ITEMS.register("mithril_tower_shield",
ShieldBuilder.create().material(MITHRIL).type(ShieldType.TOWER).build()
);
}

示例 2:能量盾牌(使用预置 FE)

Section titled “示例 2:能量盾牌(使用预置 FE)”
public static final DeferredHolder<Item, ?> FLUX_SHIELD =
ITEMS.register("flux_shield",
ShieldBuilder.create()
.type(ShieldType.TOWER)
.poweredBy(ResourceRegistry.ENERGY, 500000, 2000)
.build()
);
// Capability 自动注册 ✅ — 可被 Mekanism/Thermal 等充电器识别
// === 模组构造器中 ===
public MyMod(IEventBus modBus) {
MyDataComponents.COMPONENTS.register(modBus);
// 注册 Mana 资源类型 — 直接传 DeferredHolder
SpartanShieldsAPI.registerResourceType(new SimpleResourceType(
ResourceLocation.fromNamespaceAndPath("botania", "mana"),
Component.literal("Mana"),
MyDataComponents.STORED_MANA, // DeferredHolder IS-A Supplier
0x00C6FF
));
}
// === 物品注册 ===
IResourceType mana = ResourceRegistry.get(
ResourceLocation.fromNamespaceAndPath("botania", "mana")
).orElseThrow();
public static final DeferredHolder<Item, ?> MANA_SHIELD =
ITEMS.register("mana_shield",
ShieldBuilder.create()
.poweredBy(mana, 10000, 100)
.blockEffect(MobEffects.REGENERATION, 40, 0)
.build()
);
SpartanShieldsAPI.registerResourceType(new SimpleResourceType(
ResourceLocation.fromNamespaceAndPath("create", "stress_units"),
Component.literal("SU"),
MyDataComponents.STORED_STRESS, // DeferredHolder IS-A Supplier
0xFFED50
));
public static final DeferredHolder<Item, ?> BRASS_SHIELD =
ITEMS.register("brass_mechanical_shield",
ShieldBuilder.create()
.type(ShieldType.TOWER)
.poweredBy(
ResourceRegistry.get(ResourceLocation.fromNamespaceAndPath("create", "stress_units")).orElseThrow(),
256, 32
)
.build()
);
public static final DeferredHolder<Item, ?> MIRROR_SHIELD =
ITEMS.register("mirror_shield",
ShieldBuilder.create()
.material(SpartanShieldsAPI.createMaterial(Tiers.DIAMOND, Tags.Items.GEMS_DIAMOND))
.type(ShieldType.TOWER)
.blockHandler((shield, player, attacker, dmg) -> {
attacker.knockback(1.5,
player.getX() - attacker.getX(),
player.getZ() - attacker.getZ());
})
.build()
);
// 客户端渲染 — 在 FMLClientSetupEvent 中注册
private void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
SpartanShieldsAPI.registerTowerShieldRenderer(MIRROR_SHIELD.get(), new MyMirrorRenderer());
});
}

Minecraft 1.21+ 的 ItemColor.getColor() 必须返回 0xFFRRGGBB 格式(含 alpha 通道),否则物品栏中物品会变透明。

附属模组定义的 DataComponentType 必须包含 networkSynchronized() 调用:

// ✅ 正确
builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.INT)
// ❌ 错误 — 客户端 Tooltip 会显示 0
builder.persistent(Codec.INT)

主模组预置的 ModDataComponents.STORED_ENERGY 已正确配置同步,使用 ResourceRegistry.ENERGYResourceRegistry.MICRO_INFINITY 无需担心。

必须在模组构造器中调用 SpartanShieldsAPI.registerResourceType()。NeoForge 的模组加载顺序不保证 FMLCommonSetupEvent 的先后,太晚注册会导致其他模组的 ResourceRegistry.get() 返回空。

⚠️ DeferredHolder 在模组构造器阶段尚未绑定,调用 .get() 会抛出 NullPointerExceptionSimpleResourceTypeAbstractEnergyStorage 都提供了接受 Supplier<DataComponentType<Integer>> 的构造器,而 NeoForge 的 DeferredHolder 本身实现了 Supplier 接口,因此直接传入 DeferredHolder 即可——首次实际使用时才会解析:

// ✅ 正确 — 直接传 DeferredHolder
new SimpleResourceType(id, name, MyDataComponents.STORED_MANA, color)
// ❌ 错误 — 模组构造器中 .get() 会崩
new SimpleResourceType(id, name, MyDataComponents.STORED_MANA.get(), color)

如果两个附属模组都注册了 "botania:mana" 资源类型,后注册的会收到 IllegalArgumentException。建议联动类附属模组之间先用 ResourceRegistry.get() 检查是否已存在。

api.client 包内的接口标记了 @OnlyIn(Dist.CLIENT),服务端不可引用。绝对不要在 Item 构造函数或 DeferredRegister Supplier 中 new 渲染器实例。

必须在 FMLClientSetupEventenqueueWork() 中注册,或在模组构造器中判断 dist == Dist.CLIENT 后注册。直接在静态字段中 new 渲染器会导致专用服务器崩溃。

ShieldType.TOWER 自动应用配置中的倍率(当前 ×1.25),poweredBy 的容量也会自动乘以此倍率。

通过 ShieldBuilder.poweredBy() 创建的盾牌,主模组在 RegisterCapabilitiesEvent 时会自动扫描并调用 IResourceType.onRegisterCapabilities()附属模组无需手写任何 Capability 事件监听代码。

ShieldBuilder.build() 在返回 Supplier 前执行 validate(),不合法配置(空壳、互斥、零容量等)会立即抛出 IllegalStateException 并附带明确的错误消息。