跳到主要内容
版本:1.21.6 - 1.21.8

资源(Resources)

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

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

资产(Assets)

另请参阅:我的世界(Minecraft) Wiki上的资源包

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

NeoForge自动将所有模组资源包收集到Mod resources包中,该包位于资源包菜单中“选定包”侧的底部。目前无法禁用Mod resources包。但是,位于Mod resources包之上的资源包会覆盖下面资源包中定义的资源。这种机制允许资源包制作者覆盖您的模组资源,也允许模组开发者根据需要覆盖我的世界(Minecraft)资源。

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

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

数据(Data)

另请参阅:我的世界(Minecraft) Wiki上的数据包

与资产相反,数据(Data)是所有服务器资源的术语。类似于资源包,数据通过数据包(data packs)(或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伤害类型
datapacks内置数据包
dialog对话框菜单
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通过数据运行配置运行,该配置与客户端和服务器运行配置一起为您生成。数据运行配置遵循模组生命周期,直到注册事件触发后。然后触发其中一个GatherDataEvents,您可以在其中以数据提供器的形式注册要生成的对象,将所述对象写入磁盘,并结束过程。

有两个子类型在物理侧上操作: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()进度服务器需要额外的类才能正常工作,详情请参阅链接文章。
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:告诉数据生成器为此模组运行数据生成。由 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'
}
}