Skip to main content
Version: 1.21.4

配置(Configuration)

配置(Configuration)用于定义可以应用于一个模组(mod)实例的设置和用户偏好。NeoForge 使用基于 TOML 文件的配置系统,并通过 NightConfig 进行读取。

创建配置(Creating a Configuration)

你可以通过实现 IConfigSpec 的子类型来创建配置。NeoForge 通过 ModConfigSpec 实现了该类型,并允许你通过 ModConfigSpec.Builder 构建配置。Builder 支持通过 Builder#push 创建一个配置分区,通过 Builder#pop 离开当前分区。完成分区设置后,可以通过以下两种方法之一来构建配置:

方法描述
build创建一个 ModConfigSpec 实例。
configure创建一个包含保存配置值的类和 ModConfigSpec 的二元组。
note

ModConfigSpec.Builder#configure 通常和 static 代码块一起使用,并配合一个以 ModConfigSpec.Builder 作为构造参数的类,用于挂载和保存配置值:

// 定义字段以便后续保存配置和规范
public static final ExampleConfig CONFIG;
public static final ModConfigSpec CONFIG_SPEC;

private ExampleConfig(ModConfigSpec.Builder builder) {
// 定义配置中使用的属性
// ...
}

// CONFIG 和 CONFIG_SPEC 都是通过同一个 builder 构建的,因此我们用 static 代码块来区分属性
static {
Pair<ExampleConfig, ModConfigSpec> pair =
new ModConfigSpec.Builder().configure(ExampleConfig::new);

// 保存生成的配置对象
CONFIG = pair.getLeft();
CONFIG_SPEC = pair.getRight();
}

每个配置值都可以提供额外的上下文信息,用于扩展其行为。上下文必须在配置值完全构建之前定义:

方法(Method)描述
comment提供该配置值的描述说明。可传入多行字符串以实现多行注释。
translation为配置值的名称指定一个翻译键。
worldRestart更改该配置值前必须重启世界。
gameRestart更改该配置值前必须重启游戏。

配置值(ConfigValue)

可以使用上述上下文(如果已定义)和任意 #define 方法来构建配置值。

所有配置值方法至少需要两个参数:

  • 一个表示变量名称的路径:这是一个用 . 分隔的字符串,表示该配置值所在的分区
  • 当没有有效配置时使用的默认值

ConfigValue 的专用方法还会接收另外两个参数:

  • 一个用于确保反序列化对象有效的校验器(validator)
  • 一个表示配置值数据类型的类
// 将配置属性存储为 public final
public final ModConfigSpec.ConfigValue<String> welcomeMessage;

private ExampleConfig(ModConfigSpec.Builder builder) {
// 定义每个属性
// 其中一个属性可以是在游戏初始化时输出到控制台的消息
welcomeMessage = builder.define("welcome_message", "Hello from the config!");
}

可以通过 ConfigValue#get 获取配置值本身。为了避免多次从文件读取,配置值会被缓存。

其他配置值类型(Additional Config Value Types)

  • 范围值(Range Values)
    • 描述:值必须在定义的范围内
    • 类类型:Comparable<T>
    • 方法名:#defineInRange
    • 额外组件:
      • 配置值允许的最小值和最大值
      • 表示配置值数据类型的类
note

DoubleValueIntValueLongValue 都是范围值(range values),它们分别指定的类为 DoubleIntegerLong

  • 白名单值(Whitelisted Values)

    • 描述:值必须在提供的集合中
    • 类类型:T
    • 方法名:#defineInList
    • 额外组件:
      • 一个包含所有允许配置值的集合
  • 列表值(List Values)

    • 描述:值是一个条目列表
    • 类类型:List<T>
    • 方法名:#defineList,如果列表可以为空则用 #defineListAllowEmpty
    • 额外组件:
      • 一个 supplier,用于在配置界面新增条目时返回默认值
      • 一个校验器(validator),用于确保从列表反序列化的元素有效
      • (可选)一个校验器,确保列表条目数量不会过少或过多
  • 枚举值(Enum Values)

    • 描述:提供集合中的一个枚举值
    • 类类型:Enum<T>
    • 方法名:#defineEnum
    • 额外组件:
      • 一个 getter,用于将字符串或整数转换为枚举
      • 一个包含所有允许配置值的集合
  • 布尔值(Boolean Values)

    • 描述:一个 boolean 类型的值
    • 类类型:Boolean
    • 方法名:#define

注册配置(Registering a Configuration)

当一个 ModConfigSpec 构建完成后,必须进行注册,以便 NeoForge 能够按需加载、跟踪和同步配置设置。配置应在 mod 构造函数中通过 ModContainer#registerConfig 进行注册。注册配置时需要指定一个 类型,用于表示配置所属的端(side),还需传入 ModConfigSpec,并可选指定配置文件名。

// 在主 mod 文件中,使用 ModConfigSpec CONFIG
public ExampleMod(ModContainer container) {
...
// 注册配置
container.registerConfig(ModConfig.Type.COMMON, ExampleConfig.CONFIG);
...
}

配置类型(Configuration Types)

配置类型(Configuration types)决定了配置文件的位置、加载时机,以及该文件是否会在网络间同步。所有配置文件默认都从物理客户端的 .minecraft/config 或物理服务器的 <server_folder>/config 加载。不同配置类型之间的细微区别将在下文各小节中详细介绍。

tip

NeoForge 在其代码库中有 配置类型 的文档说明。

  • STARTUP
    • 在物理客户端和物理服务器的配置文件夹中均会加载
    • 注册时立即读取
    • 不会 在网络间同步
    • 默认文件名后缀为 -startup
warning

STARTUP 类型下注册的配置可能导致客户端与服务器之间的数据不同步,例如当配置用于禁用某些内容的注册时。因此,强烈建议不要在 STARTUP 类型的配置中控制可能会改变模组内容的功能开关。

  • CLIENT
    • 在物理客户端的配置文件夹中加载
      • 该配置类型没有服务器端位置
    • FMLCommonSetupEvent 触发前立即读取
    • 不会 在网络间同步
    • 默认文件名后缀为 -client
  • COMMON
    • 在物理客户端和物理服务器的配置文件夹中均会加载
    • FMLCommonSetupEvent 触发前立即读取
    • 不会 在网络间同步
    • 默认文件名后缀为 -common
  • SERVER
    • 在物理客户端和物理服务器的配置文件夹中均会加载
      • 可以为每个世界分别覆盖配置,方法是在以下路径添加配置文件:
        • 客户端:.minecraft/saves/<world_name>/serverconfig
        • 服务器:<server_folder>/world/serverconfig
    • ServerAboutToStartEvent 触发前立即读取
    • 会在网络间同步到客户端
    • 默认文件名后缀为 -server

配置事件(Configuration Events)

每当配置文件被加载、重新加载或卸载时,可以通过 ModConfigEvent.LoadingModConfigEvent.ReloadingModConfigEvent.Unloading 事件来执行相应操作。这些事件必须 注册 到模组事件总线(mod event bus)。

caution

这些事件会针对模组的所有配置触发;应通过提供的 ModConfig 对象来区分当前被加载或重新加载的是哪一个配置。

配置界面(Configuration Screen)

配置界面允许用户在游戏内直接编辑模组的配置值,无需手动打开或修改任何文件。该界面会自动解析你已注册的配置文件,并将其内容展示在界面上。 一个模组(mod)可以使用 NeoForge 提供的内置配置界面。模组可以通过继承 ConfigurationScreen 来修改默认界面的行为,或者自定义自己的配置界面。模组也可以完全从零开始创建自己的界面,并通过下述扩展点将这个自定义界面提供给 NeoForge。

可以通过在模组构造过程中,在 客户端 注册一个 IConfigScreenFactory 扩展点,为模组注册一个配置界面(configuration screen):

// 在主客户端模组文件中
public ExampleModClient(ModContainer container) {
...
// 这将使用 NeoForge 的 ConfigurationScreen 来显示此模组的配置
container.registerExtensionPoint(IConfigScreenFactory.class, ConfigurationScreen::new);
...
}

在游戏中,玩家可以通过进入“模组”页面,选择侧边栏中的模组,然后点击“配置”按钮来访问配置界面。启动(Startup)、通用(Common)、和客户端(Client)配置选项始终可以随时编辑。服务器(Server)配置只有在本地游玩世界时才能在界面中编辑。如果连接到服务器或其他人的局域网世界,服务器配置选项会在界面中被禁用。模组配置界面的第一页会显示所有已注册的配置文件,玩家可以选择要编辑的配置。

warning

如果你在制作配置界面,所有配置项的翻译键(translation key)都应该被添加,并且在 lang JSON 文件中定义对应的文本。

你可以通过 ModConfigSpec$Builder#translation 方法为配置项指定翻译键,因此我们可以将之前的代码扩展为:

ConfigValue<T> value = builder.comment("该值名为 'config_value_name',如果没有已有配置则会设为 defaultValue")
.translation("modid.config.config_value_name")
.define("config_value_name", defaultValue);

为了方便翻译,可以打开配置界面,浏览所有配置项及其子分区。然后返回到模组列表界面。此时,所有遇到但尚未翻译的配置项的翻译键都会被打印到控制台。这可以帮助你明确哪些内容需要翻译,以及它们的翻译键是什么。