跳到主要内容
版本:1.21.5

战利品表(Loot Tables)

战利品表是用于定义随机化战利品掉落的数据文件。可以掷出战利品表,返回一个(可能为空的)物品堆叠列表。此过程的输出取决于(伪)随机性。战利品表位于data/<mod_id>/loot_table/<name>.json。例如,泥土块使用的战利品表minecraft:blocks/dirt位于data/minecraft/loot_table/blocks/dirt.json

Minecraft在游戏中的各个点使用战利品表,包括[方块]掉落、[实体]掉落、箱子战利品、钓鱼战利品等许多其他情况。如何引用战利品表取决于上下文:

  • 默认情况下,每个方块都会收到一个关联的战利品表,位于<block_namespace>:blocks/<block_name>。可以通过在方块的Properties上调用#noLootTable来禁用此功能,导致不创建战利品表且方块不掉落任何物品;这主要由类似空气的技术方块完成。
  • 每个未调用EntityType.Builder#noLootTable的实体(通常是MobCategory#MISC中的实体)默认会收到一个关联的战利品表,位于<entity_namespace>:entities/<entity_name>。可以通过重写#getLootTable来更改此设置。例如,绵羊使用此功能根据羊毛颜色掷出不同的战利品表。
  • 结构中的箱子在其方块实体数据中指定其战利品表。Minecraft将所有箱子战利品表存储在minecraft:chests/<chest_name>中;建议但不要求在模组中遵循此做法。
  • 村民在袭击后可能向玩家投掷的礼物物品的战利品表在neoforge:raid_hero_gifts数据映射中定义。
  • 其他战利品表,例如钓鱼战利品表,在需要时从level.getServer().reloadableRegistries().getLootTable(lootTableKey)检索。所有原版战利品表位置的列表可以在BuiltInLootTables中找到。
注意

战利品表通常只应为属于您模组的内容创建。对于修改现有战利品表,应使用全局战利品修改器(GLMs)

由于战利品表系统的复杂性,战利品表由几个子系统组成,每个子系统都有不同的用途。

战利品条目(Loot Entry)

战利品条目(或战利品池条目),在代码中通过抽象类LootPoolEntryContainer表示,是一个单一的战利品元素。它可以指定一个或多个要掉落的物品。

原版总共提供8种不同的战利品条目类型。通过通用的LootPoolEntryContainer超类,它们都具有以下属性:

  • weight:权重值。默认为1。用于某些物品应比其他物品更常见的情况。例如,给定两个战利品条目,一个权重为3,一个权重为1,则第一个条目被选中的几率为75%,第二个条目为25%。
  • quality:品质值。默认为0。如果此值非零,则此值乘以幸运值(在战利品上下文中设置)并在掷出战利品表时添加到权重中。
  • conditions:应用于此战利品条目的战利品条件列表。如果一个条件失败,该条目将被视为不存在。
  • functions:应用于此战利品条目输出的战利品函数列表。

战利品条目通常分为两组:单例(具有共同的超类LootPoolSingletonContainer)和复合条目(具有共同的超类CompositeEntryBase),其中复合条目由多个单例组成。Minecraft提供以下单例类型:

  • minecraft:empty:一个空的战利品条目,表示没有物品。在代码中通过调用EmptyLootItem#emptyItem创建。
  • minecraft:item:一个单一的战利品物品条目,在掷出时掉落指定的物品。在代码中通过使用所需物品调用LootItem#lootTableItem创建。
    • 设置堆叠大小、数据组件等可以使用战利品函数完成。
  • minecraft:tag:一个标签条目,在掷出时掉落指定标签中的所有物品。根据布尔属性expand的值有两种变体。如果expand为true,则为标签中的每个物品生成一个单独的条目,否则使用一个条目来掉落所有物品。通过使用物品标签键参数调用TagEntry#tagContents(对于expand=false)或TagEntry#expandTag(对于expand=true)创建。
    • 例如,如果expand为true且标签为#minecraft:planks,则为每种木板类型生成一个条目(因此为11种原版木板生成11个条目+每种模组木板一个条目),每个条目具有指定的权重、品质和函数;而如果expand为false,则使用一个掉落所有木板的单一条目。
  • minecraft:dynamic:引用动态掉落的战利品条目。动态掉落是一个系统,用于向战利品表添加无法预先指定的条目,而是在代码中添加它们。动态掉落条目由id和实际添加物品的Consumer<ItemStack>组成。要添加动态掉落条目,请指定具有所需id的minecraft:dynamic条目,然后在战利品上下文中添加相应的消费者。使用DynamicLoot#dynamicEntry创建。
  • minecraft:loot_table:一个掷出另一个战利品表的战利品条目,将该战利品表的结果作为单个条目添加。另一个战利品表可以通过id指定或内联为整个表。在代码中通过使用ResourceLocation参数调用NestedLootTable#lootTableReference创建,或使用LootTable对象参数调用NestedLootTable#inlineLootTable创建内联战利品表。

Minecraft提供以下复合类型:

  • minecraft:group:包含其他战利品条目列表的战利品条目,按顺序运行。在代码中通过调用EntryGroup#list创建,或通过在其他LootPoolSingletonContainer.Builder上调用#append创建,每个都带有其他战利品条目构建器。
  • minecraft:sequence:类似于minecraft:group,但战利品条目在一个子条目失败时停止运行,丢弃之后的所有条目。在代码中通过调用SequentialEntry#sequential创建,或通过在其他LootPoolSingletonContainer.Builder上调用#then创建,每个都带有其他战利品条目构建器。
  • minecraft:alternatives:类似于minecraft:sequence的相反情况,但战利品条目在一个子条目成功时停止运行(而不是失败时),丢弃之后的所有条目。在代码中通过调用AlternativesEntry#alternatives创建,或通过在其他LootPoolSingletonContainer.Builder上调用#otherwise创建,每个都带有其他战利品条目构建器。

对于模组开发者,也可以定义自定义战利品条目类型

战利品池(Loot Pool)

战利品池本质上是战利品条目的列表。战利品表可以包含多个战利品池,每个战利品池将独立于其他池掷出。

战利品池可能包含以下内容:

  • entries:战利品条目列表。
  • conditions:应用于此战利品池的战利品条件列表。如果一个条件失败,将不会掷出该战利品池的任何条目。
  • functions:应用于此战利品池所有战利品条目输出的战利品函数列表。
  • rollsbonus_rolls:两个数字提供者(见下文),共同确定此战利品池将被掷出的次数。公式为rolls + bonus_rolls * luck,其中幸运值在战利品参数中设置。
  • name:战利品池的名称。NeoForge添加。这可以被GLMs使用。如果未指定,这是战利品池的哈希码,前缀为custom#

数字提供者(Number Provider)

数字提供者是在数据包上下文中获取(伪)随机数字的一种方式。主要由战利品表使用,它们也用于其他上下文,例如在世界生成中。原版提供以下六种数字提供者:

  • minecraft:constant:一个常量浮点值,在需要时四舍五入为整数。通过ConstantValue#exactly创建。
  • minecraft:uniform:均匀分布的随机整数或浮点值,设置最小和最大值。最小值和最大值之间的所有值出现的几率相同。通过UniformGenerator#between创建。
  • minecraft:binomial:二项分布的随机整数值,设置n和p值。有关这些值的含义的更多信息,请参阅二项分布。通过BinomialDistributionGenerator#binomial创建。
  • minecraft:score:给定实体目标、分数名称和(可选)缩放值,检索实体目标的给定记分板值,将其乘以给定的缩放值(如果可用)。通过ScoreboardValue#fromScoreboard创建。
  • minecraft:storage:来自给定NBT路径的命令存储的值。通过new StorageValue创建。
  • minecraft:enchantment_level:为每个附魔等级提供值的提供者。通过EnchantmentLevelProvider#forEnchantmentLevel创建,提供LevelBasedValue。有效的LevelBasedValue包括:
    • 简单常量值,未指定类型。通过LevelBasedValue#constant创建。
    • minecraft:linear:每个附魔等级线性增加的值,加上可选的常量基础值。通过LevelBasedValue#perLevel创建。
    • minecraft:levels_squared:将附魔值平方,然后向其添加可选的基础值。通过new LevelBasedValue.LevelsSquared创建。
    • minecraft:fraction:接受另外两个LevelBasedValue,使用它们创建分数。通过new LevelBasedValue.Fraction创建。
    • minecraft:clamped:接受另一个LevelBasedValue,以及最小和最大值。使用另一个LevelBasedValue计算值并钳制结果。通过new LevelBasedValue.Clamped创建。
    • minecraft:lookup:接受List<Float>和回退LevelBasedValue。在列表中查找要使用的值(等级1是列表中的第一个元素,等级2是第二个元素,依此类推),如果缺少某个等级的值,则使用回退值。通过LevelBasedValue#lookup创建。

如果需要,模组开发者也可以注册自定义数字提供者自定义基于等级的值

战利品参数(Loot Parameters)

战利品参数,内部称为ContextKey<T>,是在掷出战利品表时提供给战利品表的参数,其中T是提供的参数的类型,例如BlockPosEntity。它们可以被战利品条件战利品函数使用。例如,minecraft:killed_by_player战利品条件检查是否存在minecraft:player参数。

Minecraft提供以下战利品参数:

  • minecraft:origin:与战利品表关联的位置,例如战利品箱的位置。通过LootContextParams.ORIGIN访问。
  • minecraft:tool:与战利品表关联的物品堆叠,例如用于破坏方块的物品。这不一定是工具。通过LootContextParams.TOOL访问。
  • minecraft:enchantment_level:附魔等级,由附魔逻辑使用。通过LootContextParams.ENCHANTMENT_LEVEL访问。
  • minecraft:enchantment_active:使用的物品是否有附魔,例如由精准采集检查使用。通过LootContextParams.ENCHANTMENT_ACTIVE访问。
  • minecraft:block_state:与战利品表关联的方块状态,例如被破坏的方块状态。通过LootContextParams.BLOCK_STATE访问。
  • minecraft:block_entity:与战利品表关联的方块实体,例如与被破坏方块关联的方块实体。例如,潜影盒使用此功能将其库存保存到掉落的物品中。通过LootContextParams.BLOCK_ENTITY访问。
  • minecraft:explosion_radius:当前上下文中的爆炸半径。主要用于将爆炸衰减应用于掉落物。通过LootContextParams.EXPLOSION_RADIUS访问。
  • minecraft:this_entity:与战利品表关联的实体,通常是被杀死的实体。通过LootContextParams.THIS_ENTITY访问。
  • minecraft:damage_source:与战利品表关联的伤害源,通常是杀死实体的伤害源。通过LootContextParams.DAMAGE_SOURCE访问。
  • minecraft:attacking_entity:与战利品表关联的攻击实体,通常是实体的杀手。通过LootContextParams.ATTACKING_ENTITY访问。
  • minecraft:direct_attacking_entity:与战利品表关联的直接攻击实体。例如,如果攻击实体是骷髅,直接攻击实体将是箭。通过LootContextParams.DIRECT_ATTACKING_ENTITY访问。
  • minecraft:last_damage_player:与战利品表关联的玩家,通常是最后攻击被杀实体的玩家,即使玩家击杀是间接的(例如:玩家轻触了实体,然后它被尖刺杀死)。例如,用于仅限玩家击杀的掉落物。通过LootContextParams.LAST_DAMAGE_PLAYER访问。

可以通过使用所需id调用new ContextKey<T>来创建自定义战利品参数。由于它们仅仅是资源位置包装器,因此不需要注册。

实体目标(Entity Targets)

实体目标是战利品条件和函数中使用的一种类型,在代码中由LootContext.EntityTarget枚举表示。它们用于指定在条件或函数上下文中查询的实体战利品参数。有效值包括:

  • "this"LootContext.EntityTarget.THIS:表示"minecraft:this_entity"参数。
  • "attacker"LootContext.EntityTarget.ATTACKER:表示"minecraft:attacking_entity"参数。
  • "direct_attacker"LootContext.EntityTarget.DIRECT_ATTACKER:表示"minecraft:direct_attacking_entity"参数。
  • "attacking_player"LootContext.EntityTarget.ATTACKING_PLAYER:表示"minecraft:last_damage_player"参数。

例如,minecraft:entity_properties战利品条件接受实体目标,以允许检查所有四个战利品参数,如果这是您(作为战利品表作者)需要的。

战利品参数集(Loot Parameter Sets)

战利品参数集,也称为战利品表类型,在代码中称为ContextKeySet,是必需和可选战利品参数的集合。尽管名称如此,它们不是Set(甚至不是Collection)。相反,它们是两个Set<ContextKey<?>>的包装器,一个持有必需参数(#required),一个持有可选参数(#allowed)。它们用于验证战利品参数的用户只使用预期可用的参数,并在掷出表时验证必需参数是否存在。除此之外,它们还用于进度和附魔逻辑。

原版提供以下战利品参数集(必需参数为粗体,可选参数为斜体;代码中的名称是LootContextParamSets中的常量):

ID代码中名称指定的战利品参数用途
minecraft:emptyEMPTY不适用回退目的。
minecraft:genericALL_PARAMSminecraft:originminecraft:toolminecraft:block_stateminecraft:block_entityminecraft:explosion_radiusminecraft:this_entityminecraft:damage_sourceminecraft:attacking_entityminecraft:direct_attacking_entityminecraft:last_damage_player验证。
minecraft:commandCOMMANDminecraft:originminecraft:this_entity命令。
minecraft:selectorSELECTORminecraft:originminecraft:this_entity命令中的实体选择器。
minecraft:blockBLOCKminecraft:originminecraft:toolminecraft:block_stateminecraft:block_entityminecraft:explosion_radiusminecraft:this_entity方块破坏。
minecraft:block_useBLOCK_USEminecraft:originminecraft:block_stateminecraft:this_entity无原版用途。
minecraft:hit_blockHIT_BLOCKminecraft:originminecraft:enchantment_levelminecraft:block_stateminecraft:this_entity引雷附魔。
minecraft:chestCHESTminecraft:originminecraft:this_entityminecraft:attacking_entity战利品箱和类似容器、战利品箱矿车。
minecraft:archaeologyARCHAEOLOGYminecraft:originminecraft:this_entityminecraft:tool考古学。
minecraft:vaultVAULTminecraft:originminecraft:this_entityminecraft:tool试炼密室保险库奖励。
minecraft:entityENTITYminecraft:originminecraft:this_entityminecraft:damage_sourceminecraft:attacking_entityminecraft:direct_attacking_entityminecraft:last_damage_player实体击杀。
minecraft:shearingSHEARINGminecraft:originminecraft:this_entityminecraft:tool剪切实体,例如绵羊。
minecraft:equipmentEQUIPMENTminecraft:originminecraft:this_entity实体装备,例如僵尸。
minecraft:giftGIFTminecraft:originminecraft:this_entity袭击英雄礼物。
minecraft:barterPIGLIN_BARTERminecraft:this_entity猪灵以物易物。
minecraft:fishingFISHINGminecraft:originminecraft:toolminecraft:this_entityminecraft:attacking_entity钓鱼。
minecraft:enchanted_itemENCHANTED_ITEMminecraft:toolminecraft:enchantment_level几个附魔。
minecraft:enchanted_entityENCHANTED_ENTITYminecraft:originminecraft:enchantment_levelminecraft:this_entity几个附魔。
minecraft:enchanted_damageENCHANTED_DAMAGEminecraft:originminecraft:enchantment_levelminecraft:this_entityminecraft:damage_sourceminecraft:attacking_entityminecraft:direct_attacking_entity伤害和保护附魔。
minecraft:enchanted_locationENCHANTED_LOCATIONminecraft:originminecraft:enchantment_levelminecraft:enchantment_activeminecraft:this_entity冰霜行者和灵魂疾行附魔。
minecraft:advancement_entityADVANCEMENT_ENTITYminecraft:originminecraft:this_entity几个进度标准
minecraft:advancement_locationADVANCEMENT_LOCATIONminecraft:originminecraft:toolminecraft:block_stateminecraft:this_entity几个进度触发器
minecraft:advancement_rewardADVANCEMENT_REWARDminecraft:originminecraft:this_entity进度奖励

战利品上下文(Loot Context)

战利品上下文是一个包含掷出战利品表时情境信息的对象。信息包括:

  • 掷出战利品表的ServerLevel。通过#getLevel获取。
  • 用于掷出战利品表的RandomSource。通过#getRandom获取。
  • 战利品参数。使用#hasParameter检查存在性,使用#getParameter获取单个参数。
  • 幸运值,用于计算额外掷出次数和品质值。通常通过实体的幸运属性填充。通过#getLuck获取。
  • 动态掉落消费者。有关更多信息,请参阅上文。通过#addDynamicDrops设置。无获取器可用。

战利品表(Loot Table)

结合所有先前的元素,我们最终得到一个战利品表。战利品表JSON可以指定以下值:

  • pools:战利品池列表。
  • neoforge:conditions数据加载条件列表。警告:这些是数据加载条件,不是战利品条件
  • functions:应用于此战利品表所有战利品条目输出的战利品函数列表。
  • type:战利品参数集,用于验证战利品参数的正确使用。可选;如果不存在,将跳过验证。
  • random_sequence:此战利品表的随机序列,以资源位置的形式。随机序列由Level提供,用于在相同条件下进行一致的战利品表掷出。这通常使用战利品表的位置。

示例战利品表可能具有以下格式:

{
"type": "chest", // 战利品参数集
"neoforge:conditions": [
// 数据加载条件
],
"functions": [
// 表级战利品函数
],
"pools": [ // 战利品池列表
{
"rolls": 1, // 战利品表的掷出次数,这里使用5将产生池中的5个结果
"bonus_rolls": 0.5, // 额外掷出次数
"name": "my_pool",
"conditions": [
// 池级战利品条件
],
"functions": [
// 池级战利品函数
],
"entries": [ // 战利品表条目列表
{
"type": "minecraft:item", // 战利品条目类型
"name": "minecraft:dirt", // 类型特定属性,例如物品的名称
"weight": 3, // 条目的权重
"quality": 1, // 条目的品质
"conditions": [
// 条目级战利品条件
],
"functions": [
// 条目级战利品函数
]
}
]
}
]
}

掷出战利品表(Rolling a Loot Table)

要掷出战利品表,我们需要两样东西:战利品表本身和战利品上下文。

让我们从获取战利品表本身开始。我们可以使用level.getServer().reloadableRegistries().getLootTable(lootTableId)获取战利品表。由于战利品数据仅通过服务器可用,此逻辑必须在逻辑服务器上运行,而不是逻辑客户端。

提示

Minecraft的内置战利品表ID可以在BuiltInLootTables类中找到。方块战利品表可以通过BlockBehaviour#getLootTable获取,实体战利品表可以通过EntityType#getDefaultLootTableEntity#getLootTable获取。

现在我们有了战利品表,让我们构建我们的参数集。我们首先创建LootParams.Builder的实例:

// 确保您在服务器上,否则转换将失败。
LootParams.Builder builder = new LootParams.Builder((ServerLevel) level);

然后我们可以添加战利品上下文参数,如下所示:

// 使用您需要的任何上下文参数和值。原版参数可以在LootContextParams中找到。
builder.withParameter(LootContextParams.ORIGIN, position);
// 此变体可以接受null作为值,在这种情况下,该参数的现有值将被移除。
builder.withOptionalParameter(LootContextParams.ORIGIN, null);
// 添加动态掉落。
builder.withDynamicDrop(ResourceLocation.fromNamespaceAndPath("examplemod", "example_dynamic_drop"), stackAcceptor -> {
// 此处的一些逻辑
});
// 设置我们的幸运值。假设玩家可用。没有玩家的上下文应在此处使用0。
builder.withLuck(player.getLuck());

最后,我们可以从构建器创建LootParams并使用它们掷出战利品表:

// 如果需要,在此处指定战利品上下文参数集。
LootParams params = builder.create(LootContextParamSets.EMPTY);
// 获取战利品表。
LootTable table = level.getServer().reloadableRegistries().getLootTable(location);
// 实际掷出战利品表。
List<ItemStack> list = table.getRandomItems(params);
// 如果您正在为容器内容掷出战利品表,例如战利品箱,请使用此方法。
// 此方法负责将战利品物品正确分配到容器中。
List<ItemStack> containerList = table.fill(container, params, someSeed);
危险

LootTable另外公开了一个名为#getRandomItemsRaw的方法。与各种#getRandomItems变体不同,#getRandomItemsRaw方法不会应用全局战利品修改器。仅当您知道自己在做什么时才使用此方法。

数据生成(Datagen)

战利品表可以通过注册LootTableProvider并在构造函数中提供LootTableSubProvider列表来数据生成

@SubscribeEvent // 在模组事件总线上
public static void onGatherData(GatherDataEvent.Client event) {
// 如果添加数据包对象,首先调用event.createDatapackRegistryObjects(...)

event.createProvider((output, lookupProvider) -> new LootTableProvider(
output,
// 必需表资源位置的集合。这些稍后会被验证是否存在。
// 通常不建议模组验证存在性,
// 因此我们传入一个空集合。
Set.of(),
// 子提供者条目列表。有关此处使用什么值,请参阅下文。
List.of(...),
// 注册表访问
lookupProvider
));
}

LootTableSubProviders

LootTableSubProviders是实际生成发生的地方。要开始,我们实现LootTableSubProvider并重写#generate

public class MyLootTableSubProvider implements LootTableSubProvider {
// 参数由lambda提供(见下文)。可以存储并用于查找其他注册表条目。
public MyLootTableSubProvider(HolderLookup.Provider lookupProvider) {
// 将lookupProvider存储在字段中
}

@Override
public void generate(BiConsumer<ResourceLocation, LootTable.Builder> consumer) {
// LootTable.lootTable()返回一个我们可以添加战利品表的战利品表构建器。
consumer.accept(ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "example_loot_table"), LootTable.lootTable()
// 添加战利品表级战利品函数。此示例使用数字提供者(见下文)。
.apply(SetItemCountFunction.setCount(ConstantValue.exactly(5)))
// 添加战利品池。
.withPool(LootPool.lootPool()
// 添加战利品池级函数,类似于上文。
.apply(...)
// 添加战利品池级条件。此示例仅在降雨时掷出池。
.when(WeatherCheck.weather().setRaining(true))
// 分别设置掷出次数和额外掷出次数。
// 这两种方法都使用数字提供者。
.setRolls(UniformGenerator.between(5, 9))
.setBonusRolls(ConstantValue.exactly(1))
// 添加战利品条目。此示例返回物品战利品条目。有关更多战利品条目,请参阅下文。
.add(LootItem.lootTableItem(Items.DIRT))
)
);
}
}

一旦我们有了战利品表子提供者,我们将其添加到战利品提供者的构造函数中,如下所示:

new LootTableProvider(output, Set.of(), List.of(
new SubProviderEntry(
// 对子提供者构造函数的引用。
// 这是一个Function<HolderLookup.Provider, ? extends LootTableSubProvider>。
MyLootTableSubProvider::new,
// 关联的战利品上下文集。如果不确定使用什么,请使用empty。
LootContextParamSets.EMPTY
),
// 其他子提供者在此处(如果适用)
), lookupProvider
);

BlockLootSubProvider

BlockLootSubProvider是一个抽象辅助类,包含许多用于创建常见方块战利品表的辅助方法,例如单一物品掉落(#createSingleItemTable)、掉落创建表的方块(#dropSelf)、仅精准采集掉落(#createSilkTouchOnlyTable)、类似台阶方块的掉落(#createSlabItemTable)等许多其他方法。不幸的是,为模组使用设置BlockLootSubProvider涉及更多样板代码:

public class MyBlockLootSubProvider extends BlockLootSubProvider {
// 如果此类是战利品表提供者的内部类,则构造函数可以是私有的。
// 参数由LootTableProvider构造函数中的lambda提供。
public MyBlockLootSubProvider(HolderLookup.Provider lookupProvider) {
// 第一个参数是我们正在为其创建战利品表的方块集合。与其硬编码,
// 我们使用我们的方块注册表并在此处传递一个空集合。
// 第二个参数是特性标志集,这将是默认标志
// 除非您添加自定义标志(这超出了本文的范围)。
super(Set.of(), FeatureFlags.DEFAULT_FLAGS, lookupProvider);
}

// 此Iterable的内容用于验证。
// 我们在此处返回方块注册表值的Iterable。
@Override
protected Iterable<Block> getKnownBlocks() {
// 我们的DeferredRegister的内容。
return MyRegistries.BLOCK_REGISTRY.getEntries()
.stream()
// 在此处转换为Block,否则它将是? extends Block并且Java会抱怨。
.map(e -> (Block) e.value())
.toList();
}

// 实际添加我们的战利品表。
@Override
protected void generate() {
// 等效于调用add(MyBlocks.EXAMPLE_BLOCK.get(), createSingleItemTable(MyBlocks.EXAMPLE_BLOCK.get()));
this.dropSelf(MyBlocks.EXAMPLE_BLOCK.get());
// 添加仅精准采集战利品表。
this.add(MyBlocks.EXAMPLE_SILK_TOUCHABLE_BLOCK.get(),
this.createSilkTouchOnlyTable(MyBlocks.EXAMPLE_SILK_TOUCHABLE_BLOCK.get()));
// 其他战利品表添加在此处
}
}

然后,我们将子提供者添加到战利品表提供者的构造函数中,就像任何其他子提供者一样:

new LootTableProvider(output, Set.of(), List.of(new SubProviderEntry(
MyBlockLootTableSubProvider::new,
LootContextParamSets.BLOCK // 在此处使用BLOCK是有意义的
)), lookupProvider
);

EntityLootSubProvider

类似于BlockLootSubProviderEntityLootSubProvider提供了许多用于实体战利品表生成的辅助方法。也类似于BlockLootSubProvider,我们必须提供提供者已知实体的Stream<EntityType<?>>(而不是之前使用的Iterable<Block>)。总体而言,我们的实现看起来非常类似于BlockLootSubProvider,但所有提到的方块都替换为实体类型:

public class MyEntityLootSubProvider extends EntityLootSubProvider {
public MyEntityLootSubProvider(HolderLookup.Provider lookupProvider) {
// 与方块不同,我们不提供已知实体类型的集合。原版在此处使用自定义检查。
super(FeatureFlags.DEFAULT_FLAGS, lookupProvider);
}

// 此类使用Stream而不是Iterable,因此我们需要稍微调整一下。
@Override
protected Stream<EntityType<?>> getKnownEntityTypes() {
return MyRegistries.ENTITY_TYPES.getEntries()
.stream()
.map(e -> (EntityType<?>) e.value());
}

@Override
protected void generate() {
this.add(MyEntities.EXAMPLE_ENTITY.get(), LootTable.lootTable());
// 其他战利品表添加在此处
}
}

再次,我们将子提供者添加到战利品表提供者的构造函数中:

new LootTableProvider(output, Set.of(), List.of(new SubProviderEntry(
MyEntityLootTableSubProvider::new,
LootContextParamSets.ENTITY
)), lookupProvider
);