Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.18.x] Configurable Configurations #426

Merged
merged 5 commits into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions docs/misc/config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
Configuration
=============

Configurations define settings and consumer preferences that can be applied to a mod instance. Forge uses a configuration system using [TOML][toml] files and read with [NightConfig][nightconfig].

Creating a Configuration
------------------------

A configuration can be created using a subtype of `IConfigSpec`. Forge implements the type via `ForgeConfigSpec` and enables its construction through `ForgeConfigSpec$Builder`. The builder can separate the config values into sections via `Builder#push` to create a section and `Builder#pop` to leave a section. Afterwards, the configuration can be built using one of two methods:

Method | Description
:--- | :---
`build` | Creates the `ForgeConfigSpec`.
`configure` | Creates a pair of the class holding the config values and the `ForgeConfigSpec`.
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

!!! note
`ForgeConfigSpec$Builder#configure` is typically used with a `static` block and a class that takes in `ForgeCondifSpec$Builder` as part of its constructor to attach and hold the values:
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

```java
// In some config class
ExampleConfig(ForgeConfigSpec.Builder builder) {
// Define values here in final fields
}

// Somewhere the constructor is accessible
static {
Pair<ExampleConfig, ForgeConfigSpec> pair = new ForgeConfigSpec.Builder()
.configure(ExampleConfig::new);
// Store pair values in some constant field
}
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved
```

Each config value can be supplied with additional context to provide additional behavior. Contexts must be defined before the config value is fully built:

Method | Description
:--- | :---
`comment` | Provides a description of what the config value does. Can provide multiple strings for a multiline comment.
`translation` | Provides a translation key for the name of the config value.
`worldRestart` | The world must be restarted before the config value can be changed.

### ConfigValue

Config values can be built with the provided contexts (if defined) using any of the `#define` methods.

All config value methods take in at least two components:
* A path representing the name of the variable: a `.` separated string representing the sections the config value is in
* The default value when no valid configuration is present

The `ConfigValue` specific methods take in two additional components:
* A validator to make sure the deserialized object is valid
* A class representing the data type of the config value
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

```java
// For some ForgeConfigSpec$Builder builder
ConfigValue<T> value = builder.comment("Comment")
.define("config_value_name", defaultValue);
```

The values themselves can be obtained using `ConfigValue#get`. The values are additionally cached to prevent multiple readings from files.

#### Additional Config Value Types

* **Range Values**
* Description: Value must be between the defined bounds
* Class Type: `Comparable<T>`
* Method Name: `#defineInRange`
* Additional Components:
* The minimum and maximum the config value may be
* A class representing the data type of the config value

!!! note
`DoubleValue`s, `IntValue`s, and `LongValue`s are range values which specify the class as `Double`, `Integer`, and `Long` respectively.

* **Whitelisted Values**
* Description: Value must be in supplied collection
* Class Type: `T`
* Method Name: `#defineInList`
* Additional Components:
* A collection of the allowed values the configuration can be

* **List Values**
* Description: Value is a list of entries
* Class Type: `List<T>`
* Method Name: `#defineList`, `#defineListAllowEmpty` if list can be empty
* Additional Components:
* A validator to make sure a deserialized element from the list is valid

* **Enum Values**
* Description: An enum value in the supplied collection
* Class Type: `Enum<T>`
* Method Name: `#defineEnum`
* Additional Components:
* A getter to convert a string or integer into an enum
* A collection of the allowed values the configuration can be

* **Boolean Values**
* Description: A `boolean` value
* Class Type: `Boolean`
* Method Name: `#define`
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

Registering a Configuration
---------------------------

Once a `ForgeConfigSpec` has been built, it must be registered to allow Forge to load, track, and sync the configuration settings as required. Configurations should be registered in the mod constructor via `ModLoadingContext#registerConfig`. A configuration can be registered with a given type representing the side the config belongs to, the `ForgeConfigSpec`, and optionally a specific file name for the configuration.

Type | Loaded | Synced to Client | Stored | Default Suffix
:---: | :---: | :---: | :---: | :---
sciwhiz12 marked this conversation as resolved.
Show resolved Hide resolved
CLIENT | Client | ❌ | `.minecraft/config` | `-client`
COMMON | Both | ❌ | `.minecraft/config` | `-common`
SERVER | Server | ✔️ | `<server_folder>/serverconfig` | `-server`
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

!!! tip
Forge documents the [config types][type] within their codebase.

```java
// In the mod constructor with a ForgeConfigSpec CONFIG
ModLoadingContext.get().registerConfig(Type.COMMON, CONFIG);
```
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

Listening for Configuration Loading/Reloading
---------------------------------------------
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved

Operations that occur whenever a config is loaded or reloaded can be done using the `ModConfigEvent$Loading` and `ModConfigEvent$Reloading` events. The events must be [registered][events] to the mod event bus.

!!! warning
These events are called for all configurations for the mod; the `ModConfig` object provided should be used to denote which configuration is being loaded or reloaded.

[toml]: https://toml.io/
[nightconfig]: https://github.com/TheElectronWill/night-config
[type]: https://github.com/MinecraftForge/MinecraftForge/blob/1.18.x/fmlcore/src/main/java/net/minecraftforge/fml/config/ModConfig.java#L108-L136
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved
[events]: ../concepts/events.md#creating-an-event-handler
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ nav:
- Model Providers: 'datagen/client/modelproviders.md'
# - Server Data:
- Miscellaneous Features:
- Configuration: 'misc/config.md'
- Forge Update Checker: 'misc/updatechecker.md'
- Debug Profiler: 'misc/debugprofiler.md'
- Advanced Topics:
Expand Down