战利品表提供器

战利品表生成

构造新的 LootTableProvider 并提供 LootTableProvider$SubProviderEntry,即可为模组生成战利品表。必须将提供者添加到 DataGenerator。

LootTableProvider 的 SubProviderEntry 将 LootTableSubProvider 与上下文参数集配对;战利品表由池、条目、条件和函数等组成。

原创说明图,依据 Forge 1.21.x 官方文档 绘制。

// 在模组事件总线上
@SubscribeEvent
public void gatherData(GatherDataEvent event) {
  event.getGenerator().addProvider(
    event.includeServer(), // 仅在生成服务端数据时运行
    output -> new MyLootTableProvider(
      output,
      Collections.emptySet(), // 必须生成的表的注册名;也可留空
      List.of(subProvider1, subProvider2, /*...*/) // 生成战利品的子提供者
    )
  );
}

LootTableSubProvider

每个 LootTableProvider$SubProviderEntry 接收一个提供的 LootTableSubProvider,针对给定 LootContextParamSet 生成战利品表。LootTableSubProvider 有一个方法,接收写入器(BiConsumer<ResourceLocation, LootTable.Builder>)来生成表。

public class ExampleSubProvider implements LootTableSubProvider {
  // 供外层 Supplier 使用的工厂方法
  public ExampleSubProvider() {}
  @Override
  public void generate(BiConsumer<ResourceLocation, LootTable.Builder> writer) {
    // 调用 writer#accept 生成战利品表
  }
}

然后可在 LootTableProvider#getTables 中为任意可用的 LootContextParamSet 添加该表:

// 在传入 LootTableProvider 构造函数的列表中
new LootTableProvider.SubProviderEntry(
  ExampleSubProvider::new,
  LootContextParamSets.EMPTY // 用于 empty 参数集的战利品表生成器
)

BlockLootSubProvider 和 EntityLootSubProvider 子类

对于 LootContextParamSets#BLOCK 和 #ENTITY,分别有特殊类型 BlockLootSubProvider 和 EntityLootSubProvider,提供创建战利品表及验证其存在的额外辅助方法。

BlockLootSubProvider 构造函数接收防爆物品列表,用于确定方块被炸毁时能否生成战利品表;还接收 FeatureFlagSet,用于确定方块是否启用,从而是否为其生成战利品表。

// 在 BlockLootSubProvider 子类中
public MyBlockLootSubProvider() {
  super(Collections.emptySet(), FeatureFlags.REGISTRY.allFlags());
}

EntityLootSubProvider 构造函数接收 FeatureFlagSet,用于确定实体类型是否启用,从而是否为其生成战利品表。

public MyEntityLootSubProvider() {
  super(FeatureFlags.REGISTRY.allFlags());
}

使用时,必须分别通过 BlockLootSubProvider#getKnownBlocks 和 EntityLootSubProvider#getKnownEntityTypes 提供所有注册对象。这些方法确保可迭代集合中的所有对象都有战利品表。

提示:如果使用 DeferredRegister 注册模组对象,可通过 DeferredRegister#getEntries 为 #getKnown* 方法提供条目:

// 在 BlockLootSubProvider 子类中,假设存在 DeferredRegister BLOCK_REGISTRAR
@Override
protected Iterable<Block> getKnownBlocks() {
  return BLOCK_REGISTRAR.getEntries() // 获取注册条目
    .stream() // 流式处理包装对象
    .flatMap(RegistryObject::stream) // 获取可用对象
    ::iterator; // 创建可迭代对象
}

实现 #generate 方法即可添加战利品表:

@Override
public void generate() {
  // 在此添加战利品表
}

战利品表构建器

生成战利品表时,LootTableSubProvider 以 LootTable$Builder 接收表,随后设置 LootTableProvider$SubProviderEntry 指定的 LootContextParamSet 并通过 #build 构建。构建前可指定影响表运作方式的条目、条件和修饰器。

注意:战利品表功能十分广泛,本文无法完整涵盖,只简述各组件。各组件的具体子类型可以通过 IDE 查找,实现留给读者自行练习。

LootTable

战利品表是基础对象,可通过 LootTable#lootTable 转为所需的 LootTable$Builder。构建时可通过 #withPool 添加按指定顺序应用的战利品池列表,也可通过 #apply 添加函数以修改这些池产生的物品。

LootPool

战利品池表示一组操作,可通过 LootPool#lootPool 生成 LootPool$Builder。每个池可通过 #add 指定定义池内操作的条目,通过 #when 指定是否执行操作的条件,通过 #apply 指定修改条目产生物品的函数。可通过 #setRolls 指定池执行次数;还可通过 #setBonusRolls 指定受执行者幸运值影响的额外执行次数。

LootPoolEntryContainer

战利品条目定义被选中时的操作,通常生成物品。每个条目都有关联的已注册 LootPoolEntryType,以及继承 LootPoolEntryContainer$Builder 的构建器。可通过 #append 同时执行多个条目,通过 #then 顺序执行直到某个条目失败,也可通过 #otherwise 在失败时回退到另一个条目。

LootItemCondition

战利品条件定义执行某项操作必须满足的要求。每个条件都有关联的已注册 LootItemConditionType 和继承 LootItemCondition$Builder 的构建器。默认所有指定条件都必须返回 true 才执行;也可通过 #or 指定只需一个为真,或通过 #invert 反转条件结果。

LootItemFunction

战利品函数在结果送入输出前修改它。每个函数都有关联的已注册 LootItemFunctionType 和继承 LootItemFunction$Builder 的构建器。

NbtProvider

NBT 提供者是由 CopyNbtFunction 定义的特殊函数,用于指定从哪里获取标签信息。每个提供者都有关联的已注册 LootNbtProviderType。

NumberProvider

数字提供者决定战利品池执行次数。每个提供者都有关联的已注册 LootNumberProviderType。

ScoreboardNameProvider

记分板提供者是 ScoreboardValue 定义的特殊数字提供者,指定从哪个记分板名称读取执行次数。每个提供者都有关联的已注册 LootScoreProviderType。

原文:Loot Table Generation。