跳到主要内容
版本:1.21.4

战利品表(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。有效的LevelBasedValues包括:
    • 简单常量值,没有指定类型。通过LevelBasedValue#constant创建。
    • minecraft:linear:每个附魔等级线性增加的值,加上可选的常量基础值。通过LevelBasedValue#perLevel创建。
    • minecraft:levels_squared:将附魔值平方,然后向其添加可选的基础值。通过new LevelBasedValue.LevelsSquared创建。
    • minecraft:fraction:接受另外两个LevelBasedValues,使用它们创建分数。通过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)

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

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

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

战利品上下文(Loot Context)

战利品上下文是包含滚动战利品表的情境信息的对象。信息包括:

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

战利品表(Loot Table)

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

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

An example loot table could have the following format:

{
"type": "chest", // loot parameter set
"neoforge:conditions": [
// data load conditions
],
"functions": [
// table-wide loot functions
],
"pools": [ // list of loot pools
{
"rolls": 1, // amount of rolls of the loot table, using 5 here will yield 5 results from the pool
"bonus_rolls": 0.5, // amount of bonus rolls
"name": "my_pool",
"conditions": [
// pool-wide loot conditions
],
"functions": [
// pool-wide loot functions
],
"entries": [ // list of loot table entries
{
"type": "minecraft:item", // loot entry type
"name": "minecraft:dirt", // type-specific properties, for example the name of the item
"weight": 3, // weight of an entry
"quality": 1, // quality of an entry
"conditions": [
// entry-wide loot conditions
],
"functions": [
// entry-wide loot 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
);