跳到主要内容
版本:1.21.5

资源(Resources)

资源(Resources)是游戏使用的外部文件,但不是代码。最突出的资源类型是纹理,然而,Minecraft生态系统中存在许多其他类型的资源。当然,所有这些资源都需要代码端的消费者,因此消费系统也分组在本节中。

Minecraft通常有两种资源:用于逻辑客户端(logical client)的资源,称为资产(assets),以及用于逻辑服务器(logical server)的资源,称为数据(data)。资产主要是仅显示信息,例如纹理、显示模型、翻译或声音,而数据包括影响游戏玩法的各种内容,例如战利品表、配方或世界生成信息。它们分别从资源包和数据包加载。NeoForge为每个模组生成内置的资源包和数据包。

资源包和数据包通常都需要一个pack.mcmeta文件;然而,现代NeoForge在运行时为你生成这些文件,所以你不需要担心它。

如果你对某些内容的格式感到困惑,请查看原版资源。你的NeoForge开发环境不仅包含原版代码,还包含原版资源。它们可以在外部资源部分(IntelliJ)/项目库部分(Eclipse)中找到,名称为ng_dummy_ng.net.minecraft:client:client-extra:<minecraft_version>(用于Minecraft资源)或ng_dummy_ng.net.neoforged:neoforge:<neoforge_version>(用于NeoForge资源)。

资产

另请参见:Minecraft Wiki上的资源包(Resource Packs)

资产(Assets),或客户端资源,是所有仅与客户端(client)相关的资源。它们从资源包加载,有时也称为旧术语纹理包(源于旧版本,当时它们只能影响纹理)。资源包基本上是一个assets文件夹。assets文件夹包含资源包包含的各种命名空间的子文件夹;每个命名空间都是一个子文件夹。例如,一个模组ID为coolmod的资源包可能包含一个coolmod命名空间,但可能还包括其他命名空间,例如minecraft

NeoForge自动将所有模组资源包收集到Mod resources包中,该包位于资源包菜单的"已选包"侧底部。目前无法禁用Mod resources包。然而,位于Mod resources包上方的资源包会覆盖下方资源包中定义的资源。这种机制允许资源包制作者覆盖你的模组资源,也允许模组开发者在需要时覆盖Minecraft资源。

资源包可能包含影响以下内容的文件夹:

文件夹名称内容
atlases纹理图集源
blockstates方块状态文件(Blockstate Files)
equipment装备信息(Equipment Info)
font字体定义
items客户端物品(Client Items)
lang翻译文件(Translation Files)
models模型(Models)
particles粒子定义(Particle Definitions)
post_effect后期处理屏幕效果
shaders元数据、片段和顶点着色器
sounds声音文件(Sound Files)
texts杂项文本文件
textures纹理(Textures)

数据

另请参见:Minecraft Wiki上的数据包(Data Packs)

与资产相反,数据(data)是所有服务器(server)资源的术语。类似于资源包,数据通过数据包(或datapacks)加载。像资源包一样,数据包由一个pack.mcmeta文件和一个名为data的根文件夹组成。然后,再次像资源包一样,data文件夹包含数据包包含的各种命名空间的子文件夹;每个命名空间都是一个子文件夹。例如,一个模组ID为coolmod的数据包可能包含一个coolmod命名空间,但可能还包括其他命名空间,例如minecraft

NeoForge在创建新世界时自动应用所有模组数据包。目前无法禁用模组数据包。然而,大多数数据文件可以被具有更高优先级的数据包覆盖(从而通过用空文件替换它们来移除)。可以通过将额外的数据包放置在世界datapacks子文件夹中,然后通过/datapack命令启用或禁用来启用或禁用它们。

信息

目前没有内置方法将一组自定义数据包应用于每个世界。然而,有许多模组实现了这一点。

数据包可能包含影响以下内容的文件夹:

文件夹名称内容
advancement进度
banner_pattern旗帜图案
cat_variant, chicken_variant, cow_variant, frog_variant, pig_variant, wolf_variant实体变种
damage_type伤害类型
enchantment, enchantment_provider附魔
instrument, jukebox_song, wolf_sound_variant声音参考元数据
painting_variant画作
loot_table战利品表
recipe配方
tags标签
test_environment, test_instance游戏测试
trial_spawner战斗挑战
trim_material, trim_pattern盔甲纹饰
neoforge/data_maps数据映射
neoforge/loot_modifiers全局战利品修改器
dimension, dimension_type, structure, worldgen, neoforge/biome_modifier世界生成文件

此外,它们还可能包含一些与命令集成的系统的子文件夹。这些系统很少与模组一起使用,但无论如何都值得一提:

文件夹名称内容
chat_type聊天类型
function函数
item_modifier物品修改器
predicate谓词

pack.mcmeta

另请参见:Minecraft Wiki上的pack.mcmeta(资源包)pack.mcmeta(数据包)

pack.mcmeta 文件保存资源包或数据包的元数据。对于模组,NeoForge 使此文件过时,因为 pack.mcmeta 是合成生成的。如果您仍然需要 pack.mcmeta 文件,完整的规范可以在链接的 Minecraft Wiki 文章中找到。

数据生成(Data Generation)

数据生成,俗称 datagen,是一种以编程方式生成 JSON 资源文件的方法,以避免手动编写它们的繁琐且容易出错的过程。这个名称有点误导性,因为它既适用于资产也适用于数据。

Datagen 通过 Data 运行配置运行,该配置与 Client 和 Server 运行配置一起为您生成。数据运行配置遵循模组生命周期,直到注册表事件触发之后。然后它触发一个 GatherDataEvent,您可以在其中以数据提供者的形式注册要生成的对象,将所述对象写入磁盘,并结束该过程。

有两种子类型在物理侧上运行:GatherDataEvent.ClientGatherDataEvent.ServerGatherDataEvent.Client 可能包含所有要生成的提供者。另一方面,GatherDataEvent.Server 可能只包含用于生成数据包条目的提供者。

备注

关于如何注册您的提供者有两个建议。前者是在 GatherDataEvent.Client 中注册所有提供者,并使用 runClientData 任务生成数据。后者是将客户端提供者注册到 GatherDataEvent.Client,将服务器提供者注册到 GatherDataEvent.Server,分别通过运行 runClientDatarunServerData 任务来生成它们。

由于 MDK 通过设置默认的 clientData 配置使用前一种解决方案,所有显示的示例都将使用前一种方法,将所有提供者注册到 GatherDataEvent.Client

所有数据提供者都扩展 DataProvider 接口,通常需要重写一个方法。以下是 Minecraft 和 NeoForge 提供的重要数据生成器列表(链接的文章提供了更多信息,例如辅助方法):

方法生成内容备注
ModelProviderregisterModels()模型、方块状态文件、客户端物品客户端
LanguageProvideraddTranslations()翻译客户端还需要在构造函数中传递语言。
ParticleDescriptionProvideraddDescriptions()粒子定义客户端
SoundDefinitionsProviderregisterSounds()声音定义客户端
SpriteSourceProvidergather()精灵源/纹理图集客户端
AdvancementProvidergenerate()进度服务器确保使用 NeoForge 变体,而不是 Minecraft 的。
LootTableProvidergenerate()战利品表服务器需要额外的方法和类才能正常工作,有关详细信息,请参阅链接的文章。
RecipeProviderbuildRecipes(RecipeOutput)配方服务器
TagsProvider 的各种子类addTags(HolderLookup.Provider)标签服务器存在几个专门的子类,有关详细信息,请参阅链接的文章。
DataMapProvidergather()数据映射条目服务器
GlobalLootModifierProviderstart()全局战利品修改器服务器
DatapackBuiltinEntriesProviderN/A数据包内置条目,例如世界生成和伤害类型服务器没有方法重写,而是在构造函数的 lambda 中添加条目。有关详细信息,请参阅链接的文章。
JsonCodecProvider(抽象类)gather()具有编解码器的对象两者可以扩展以用于任何具有编解码器来编码数据的对象。

所有这些提供者都遵循相同的模式。首先,您创建一个子类并添加要生成的自己的资源。然后,您将提供者添加到事件处理程序中的事件。使用 RecipeProvider 的示例:

public class MyRecipeProvider extends RecipeProvider {
public MyRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
super(registries, output);
}

@Override
protected void buildRecipes() {
// 在此处注册您的配方。
}

// 数据提供者类
public static class Runner extends RecipeProvider.Runner {

public Runner(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(output, registries);
}

@Override
protected abstract RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
return new MyRecipeProvider(registries, output);
}
}
}

// 在某个事件处理程序类中
@SubscribeEvent // 在模组事件总线上
public static void gatherData(GatherDataEvent.Client event) {
// 数据提供者应首先调用 event.createDatapackRegistryObjects(...)
// 来注册它们的数据包注册表对象。这允许其他提供者
// 在它们自己的数据生成期间使用这些对象。

// 从那里,提供者通常可以使用 event.createProvider(...) 注册,
// 它充当一个函数,提供 PackOutput 和可选的
// CompletableFuture<HolderLookup.Provider>。

// 注册提供者。
event.createProvider(MyRecipeProvider.Runner::new);
// 其他数据提供者在此处。

// 如果要在全局包内创建数据包,可以调用
// DataGenerator#getBuiltinDatapack。从那里,您必须使用
// PackGenerator#addProvider 方法将任何提供者添加到该包。
DataGenerator.PackGenerator examplePack = event.getGenerator().getBuiltinDatapack(
true, // 应始终为 true。
"examplemod", // 模组 ID。
"example_pack" // 包的名称。
);

examplePack.addProvider(output -> ...);
}

事件提供了一些辅助工具和上下文供您使用:

  • event.createDatapackRegistryObjects(...) 使用提供的 RegistrySetBuilder 创建并注册一个 DatapackBuiltinEntriesProvider。它还强制任何将来使用的查找提供者包含您的数据生成条目。
  • event.createProvider(...) 通过提供 PackOutput 和可选的 CompletableFuture<HolderLookup.Provider> 作为 lambda 的一部分来注册提供者。
  • event.createBlockAndItemTags(...) 通过使用 TagsProvider<Block> 构造 TagsProvider<Item> 来注册 TagsProvider<Block>TagsProvider<Item>
  • event.getGenerator() 返回您注册提供者的 DataGenerator
  • event.getPackOutput() 返回一个 PackOutput,某些提供者使用它来确定其文件输出位置。
  • event.getResourceManager(PackType) 返回一个 ResourceManager,提供者可以使用它来检查已存在的文件。
  • event.getLookupProvider() 返回一个 CompletableFuture<HolderLookup.Provider>,主要由标签和数据生成注册表用于引用其他可能尚未存在的元素。
  • event.includeDev()event.includeReports()boolean 方法,允许您检查是否启用了特定的命令行参数(见下文)。

命令行参数(Command Line Arguments)

数据生成器可以接受几个命令行参数:

  • --mod examplemod:告诉数据生成器为此模组运行 datagen。由 NeoGradle 自动为所属模组 ID 添加,如果您在一个项目中有多个模组,请添加此参数。
  • --output path/to/folder:告诉数据生成器输出到给定文件夹。建议使用 Gradle 的 file(...).getAbsolutePath() 为您生成绝对路径(相对于项目根目录的路径)。默认为 file('src/generated/resources').getAbsolutePath()
  • --existing path/to/folder:告诉数据生成器在检查现有文件时考虑给定文件夹。与输出一样,建议使用 Gradle 的 file(...).getAbsolutePath()
  • --existing-mod examplemod:告诉数据生成器在检查现有文件时考虑给定模组 JAR 文件中的资源。
  • 生成器模式(所有这些都是布尔参数,不需要任何额外参数):
    • --includeDev:是否运行开发工具。通常不应由模组使用。在运行时使用 GatherDataEvent#includeDev() 检查。
    • --includeReports:是否转储注册对象列表。在运行时使用 GatherDataEvent#includeReports() 检查。
    • --all:启用所有生成器模式。

所有参数都可以通过将以下内容添加到您的 build.gradle 来添加到运行配置中:

runs {
// 其他运行配置在此处

clientData {
arguments.addAll '--arg1', 'value1', '--arg2', 'value2', '--all' // 布尔参数没有值
}
}

例如,要复制默认参数,您可以指定以下内容:

runs {
// 其他运行配置在此处

clientData {
arguments.addAll '--mod', 'examplemod', // 插入您自己的模组 ID
'--output', file('src/generated/resources').getAbsolutePath(),
'--all'
}
}