标签
标签是同一类型注册对象的列表,从数据文件加载,可用于成员检查。例如,木棍配方接受任意木板组合,即所有带 minecraft:planks 标签的物品。通常用 # 前缀区分标签和普通对象,例如 #minecraft:planks 与 minecraft:oak_planks。
任何注册表都可有标签。方块和物品最常见,流体、实体类型、伤害类型等也常使用。也可按需创建自己的标签。
Minecraft 注册表的标签路径为 data/<tag_namespace>/tags/<registry_path>/<tag_path>.json,其他注册表则为 data/<tag_namespace>/tags/<registry_namespace>/<registry_path>/<tag_path>.json。例如 minecraft:planks 物品标签位于 data/minecraft/tags/item/planks.json。
说明 与大多数 NeoForge 数据文件不同,其新增标签通常使用 c 命名空间,例如 c:ingots/gold,以便与 Fabric 统一,满足多加载器开发者的需求。但某些与 NeoForge 系统紧密相关的标签例外,例如许多伤害类型标签。
标签文件通常累加而非覆盖。同 ID 的多个数据包标签会合并内容,除非另有指定;这区别于大多数直接替换已有内容的数据文件。
文件格式
{
// The values of the tag.
"values": [
// A value object. Must specify the id of the object to add, and whether it is required.
// If the entry is required, but the object is not present, the tag will not load. The "required" field
// is technically optional, but when removed, the entry is equivalent to the shorthand below.
{
"id": "examplemod:example_ingot",
"required": false
}
// Shorthand for {"id": "minecraft:gold_ingot", "required": true}, i.e. a required entry.
"minecraft:gold_ingot",
// A tag object. Distinguished from regular entries by the leading #. In this case, all planks
// will be considered entries of the tag. Like normal entries, this can also have the "id"/"required" format.
// Warning: Circular tag dependencies will lead to a datapack not being loaded!
"#minecraft:planks"
],
// Whether to remove all pre-existing entries before adding your own (true) or just add your own (false).
// This should generally be false, the option to set this to true is primarily aimed at pack developers.
"replace": false,
// A finer-grained way to remove entries from the tag again, if present. Optional, NeoForge-added.
// Entry syntax is the same as in the "values" array.
"remove": [
"minecraft:iron_ingot"
]
}
查找和命名标签
查找现有标签时建议依次:
- 检查 Minecraft 的 BlockTags、ItemTags、EntityTypeTags 等。
- 检查 NeoForge 的 Tags.Blocks、Tags.Items、Tags.EntityTypes 等。
- 如果都没有,则自行创建。
创建时考虑用途:改变自己 Mod 行为的标签应放在自己的命名空间,例如决定某物可在哪种方块生成。其他 Mod 也可能使用的标签(例如新金属、宝石)应放在 c。其余默认使用自己的命名空间。
命名应使用复数,如 minecraft:planks、c:ingots。同类多个对象应分文件夹,并有一个总标签,例如 c:ingots/iron、c:ingots/gold,以及包含两者的 c:ingots。这是 NeoForge 惯例,原版多数标签并不遵循。
使用标签
在代码中使用注册表键与资源位置创建 TagKey<T>,T 为 Block、Item、EntityType<?> 等标签对象类型:
public static final TagKey<Block> MY_TAG = TagKey.create(
// The registry key. The type of the registry must match the generic type of the tag.
Registries.BLOCK,
// The location of the tag. This example will put our tag at data/examplemod/tags/blocks/example_tag.json.
ResourceLocation.fromNamespaceAndPath("examplemod", "example_tag")
);
警告 TagKey 是 record,因此构造函数公开,但不应直接调用,否则可能导致标签条目查询等问题。
随后即可操作标签。先检查对象是否属于标签。以下以方块为例,除特别说明外,其他类型功能相同:
// Check whether dirt is in our tag.
boolean isInTag = BuiltInRegistries.BLOCK.getOrCreateTag(MY_TAG).stream().anyMatch(e -> e == Items.DIRT);
因为上述写法较长,最常用的 BlockState 和 ItemStack 提供 #is 辅助方法:
// Check whether the blockState's block is in our tag.
boolean isInBlockTag = blockState.is(MY_TAG);
// Check whether the itemStack's item is in our tag. Assumes the existence of MY_ITEM_TAG as a TagKey<Item>.
boolean isInItemTag = itemStack.is(MY_ITEM_TAG);
也可以获取条目流:
Stream<Block> blocksInTag = BuiltInRegistries.BLOCK.getOrCreateTag(MY_TAG).stream();
出于性能考虑,建议在字段中缓存条目,并在标签重载时使缓存失效,可通过 TagsUpdatedEvent 监听:
public class MyTagsCacheClass {
private static Set<Block> blocksInTag = null;
public static Set<Block> getBlockTagContents() {
if (blocksInTag == null) {
// Wrap as an unmodifiable set, as we're not supposed to modify this anyway
blocksInTag = Collections.unmodifiableSet(BuiltInRegistries.BLOCK.getOrCreateTag(MY_TAG).stream().collect(Collectors.toSet()));
}
return blocksInTag;
}
public static void invalidateCache() {
blocksInTag = null;
}
}
// In some event handler class
@SubscribeEvent // on the game event bus
public static void onTagsUpdated(TagsUpdatedEvent event) {
MyTagsCacheClass.invalidateCache();
}
数据生成
标签也可生成。每种标签都有自己的生成基类,因此需要对应的提供器类。它们均继承 TagsProvider<T>,T 为标签类型。常用类型如下:
| 类型 | 标签提供器类 |
|---|---|
BannerPattern |
BannerPatternTagsProvider |
Biome |
BiomeTagsProvider |
Block |
BlockTagsProvider |
CatVariant |
CatVariantTagsProvider |
DamageType |
DamageTypeTagsProvider |
Enchantment |
EnchantmentTagsProvider |
EntityType |
EntityTypeTagsProvider |
FlatLevelGeneratorPreset |
FlatLevelGeneratorPresetTagsProvider |
Fluid |
FluidTagsProvider |
GameEvent |
GameEventTagsProvider |
Instrument |
InstrumentTagsProvider |
Item |
ItemTagsProvider |
PaintingVariant |
PaintingVariantTagsProvider |
PoiType |
PoiTypeTagsProvider |
Structure |
StructureTagsProvider |
WorldPreset |
WorldPresetTagsProvider |
IntrinsicHolderTagsProvider<T> 是 TagsProvider<T> 的子类,也是 BlockTagsProvider、ItemTagsProvider、FluidTagsProvider、EntityTypeTagsProvider 与 GameEventTagsProvider 的共同父类。为简便,下面称它们为内在提供器;它们有额外生成功能。
以方块标签为例,其他类型的用法相同:
public class MyBlockTagsProvider extends BlockTagsProvider {
// Get parameters from GatherDataEvent.
public MyBlockTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> lookupProvider, ExistingFileHelper existingFileHelper) {
super(output, lookupProvider, ExampleMod.MOD_ID, existingFileHelper);
}
// Add your tag entries here.
@Override
protected void addTags(HolderLookup.Provider lookupProvider) {
// Create a tag builder for our tag. This could also be e.g. a vanilla or NeoForge tag.
tag(MY_TAG)
// Add entries. This is a vararg parameter.
// Non-intrinsic providers must provide ResourceKeys here instead of the actual objects.
.add(Blocks.DIRT, Blocks.COBBLESTONE)
// Add optional entries that will be ignored if absent. This example uses Botania's Pure Daisy.
// Unlike #add, this is not a vararg parameter.
.addOptional(ResourceLocation.fromNamespaceAndPath("botania", "pure_daisy"))
// Add a tag entry.
.addTag(BlockTags.PLANKS)
// Add multiple tag entries. This is a vararg parameter.
// Can cause unchecked warnings that can safely be suppressed.
.addTags(BlockTags.LOGS, BlockTags.WOODEN_SLABS)
// Add an optional tag entry that will be ignored if absent.
.addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "ingots/tin"))
// Add multiple optional tag entries. This is a vararg parameter.
// Can cause unchecked warnings that can safely be suppressed.
.addOptionalTags(ResourceLocation.fromNamespaceAndPath("c", "nuggets/tin"), ResourceLocation.fromNamespaceAndPath("c", "storage_blocks/tin"))
// Set the replace property to true.
.replace()
// Set the replace property back to false.
.replace(false)
// Remove entries. This is a vararg parameter. Accepts either resource locations, resource keys,
// tag keys, or (intrinsic providers only) direct values.
// Can cause unchecked warnings that can safely be suppressed.
.remove(ResourceLocation.fromNamespaceAndPath("minecraft", "crimson_slab"), ResourceLocation.fromNamespaceAndPath("minecraft", "warped_slab"));
}
}
生成的 JSON 如下:
{
"values": [
"minecraft:dirt",
"minecraft:cobblestone",
{
"id": "botania:pure_daisy",
"required": false
},
"#minecraft:planks",
"#minecraft:logs",
"#minecraft:wooden_slabs",
{
"id": "c:ingots/tin",
"required": false
},
{
"id": "c:nuggets/tin",
"required": false
},
{
"id": "c:storage_blocks/tin",
"required": false
}
],
"remove": [
"minecraft:crimson_slab",
"minecraft:warped_slab"
]
}
与其他提供器一样,将每个标签提供器加入 GatherDataEvent:
@SubscribeEvent // on the mod event bus
public static void gatherData(GatherDataEvent event) {
PackOutput output = generator.getPackOutput();
CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
// other providers here
event.getGenerator().addProvider(
event.includeServer(),
new MyBlockTagsProvider(output, lookupProvider, existingFileHelper)
);
}
ItemTagsProvider 另有 #copy 辅助方法,用于常见的物品标签与方块标签镜像需求:
// In an ItemTagsProvider's #addTags method, assuming types TagKey<Block> and TagKey<Item> for the two parameters.
copy(EXAMPLE_BLOCK_TAG, EXAMPLE_ITEM_TAG);
自定义标签提供器
自定义注册表,或默认没有提供器的原版/NeoForge 注册表,也可以定义提供器,例如配方类型标签:
public class MyRecipeTypeTagsProvider extends TagsProvider<RecipeType<?>> {
// Get parameters from GatherDataEvent.
public MyRecipeTypeTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> lookupProvider, ExistingFileHelper existingFileHelper) {
// Second parameter is the registry key we are generating the tags for.
super(output, Registries.RECIPE_TYPE, lookupProvider, ExampleMod.MOD_ID, existingFileHelper);
}
@Override
protected void addTags(HolderLookup.Provider lookupProvider) { /*...*/ }
}
适用时也可继承 IntrinsicHolderTagsProvider<T>,直接传对象而非仅资源键。这需要额外提供一个将对象转换为资源键的函数,例如属性标签:
public class MyAttributeTagsProvider extends TagsProvider<Attribute> {
// Get parameters from GatherDataEvent.
public MyAttributeTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> lookupProvider, ExistingFileHelper existingFileHelper) {
super(output,
Registries.ATTRIBUTE,
lookupProvider,
// A function that, given an Attribute, returns a ResourceKey<Attribute>.
attribute -> BuiltInRegistries.ATTRIBUTE.getResourceKey(attribute).orElseThrow(),
ExampleMod.MOD_ID,
existingFileHelper);
}
// Attributes can now be used here directly, instead of just their resource keys.
@Override
protected void addTags(HolderLookup.Provider lookupProvider) { /*...*/ }
}
说明 TagsProvider 还公开 #getOrCreateRawBuilder,返回 TagBuilder,可向标签添加原始 ResourceLocation。TagsProvider#tag 返回的
TagAppender<T>只是其包装。
来源: NeoForged/Documentation(1.21.1)。中文翻译依据提交
4a680cdd4d15。