Configs

From Forge Community Wiki
Revision as of 14:44, 17 November 2021 by TelepathicGrunt (talk | contribs) (How to create and register config files)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Creating configs in Forge is fairly simple as Forge provides a ton of tools for configs. In addition, Forge will automatically update their values as the config files are edited and cache the values so you do not need to do so.

To begin, create a new class file and add this:

```java

   public static final ForgeConfigSpec GENERAL_SPEC;
   
   static {
       ForgeConfigSpec.Builder configBuilder = new ForgeConfigSpec.Builder();
       setupConfig(configBuilder);
       GENERAL_SPEC = configBuilder.build();
   }
   private static void setupConfig(ForgeConfigSpec.Builder builder) { 
   }

```

ForgeConfigSpec is what will ultimately hold all the data and info about how to make and read your config file. We will be registering this later. In the static block, this will create the builder for ForgeConfigSpec, pass it into setupConfig where we will add all the config entries we want, and then we build the final ForgeConfigSpec to store into GENERAL_SPEC.


Now for creating config entries, lets add an integer config entry by creating a public static field for it and use builder.defineInRange to define it. ```java

   public static ForgeConfigSpec.IntValue exampleIntConfigEntry;
   private static void setupConfig(ForgeConfigSpec.Builder builder) {
       exampleIntConfigEntry = builder.defineInRange("example_int_config_entry", 5, 2, 50);
   }

```

Here, setupConfig method will add to the builder that there should be a "example_int_config_entry" entry in the toml file, it has a default value of 5, and will only accept a user-entered value between 2 and 50. The it assigns that resultant ForgeConfigSpec.DoubleValue to the exampleIntConfigEntry field. Now the exampleIntConfigEntry field can be call with `.get()` anywhere in our code to get the current config value for that config entry at the time.

There are many kinds of config entries you can make. Some of the more commonly used ones are: ForgeConfigSpec.IntValue - uses defineInRange ForgeConfigSpec.DoubleValue - uses defineInRange ForgeConfigSpec.LongValue - uses defineInRange ForgeConfigSpec.BooleanValue - uses define ForgeConfigSpec.ConfigValue<String> - uses define ForgeConfigSpec.ConfigValue<List<? extends String>> - uses defineList (IMPORTANT, do not use .define for lists. Always .defineList)

As for the methods you can use for each of these config types: .define - takes the default config value. .defineInRange - takes the default, the minimum, and maximum config values in that order. .defineList - takes the default list to use and a validator to run on each list entry when the user tries to change the config file to make sure it is correctly edited by user.

Furthermore, you may attach a comment or translation key to your builder that is creating the config entries. And using `builder.push("...")` and `builder.pop();` before and after some config entries will put them into a category (comments can be attached to categories as well). Here is a large example of all this:

```java

   public static ForgeConfigSpec.IntValue exampleIntConfigEntry;
   public static ForgeConfigSpec.DoubleValue exampleDoubleConfigEntry;
   public static ForgeConfigSpec.ConfigValue<Double> exampleUnboundedDoubleConfigEntry;
   public static ForgeConfigSpec.LongValue exampleLongConfigEntry;
   public static ForgeConfigSpec.BooleanValue exampleBooleanConfigEntry;
   public static ForgeConfigSpec.ConfigValue<String> exampleStringConfigEntry;
   public static ForgeConfigSpec.ConfigValue<List<? extends String>> exampleStringListConfigEntry;
   private static void setupConfig(ForgeConfigSpec.Builder builder) {
       builder.comment(" This category holds configs that uses numbers.")
       builder.push("Numeric Config Options");
         exampleIntConfigEntry = builder.defineInRange("example_int_config_entry", 5, 2, 50);
         exampleDoubleConfigEntry = builder.defineInRange("example_double_config_entry", 10D, 0D, 100D);
         exampleUnboundedDoubleConfigEntry = builder
            .comment("This comment will be attached to example_unbounded_double_config_entry in the config file.")
            .define("example_unbounded_double_config_entry", 1000D);
         exampleLongConfigEntry = builder.defineInRange("example_long_config_entry", 4L, -900L, 900L);
       builder.pop();


       builder.comment(" This category holds configs that uses numbers.")
       builder.push("String Config Options");
         exampleStringConfigEntry = builder
            .comment("This config holds a single string.")
            .define("example_string_config_entry", "player444");
         builder.comment(" This category will be nested inside the String Config Options category.")
         builder.push("Nested Category");
           exampleStringListConfigEntry = builder
             .comment("This config entry will hold a list of strings.")
             .defineList("example_string_list_config_entry", Arrays.asList("pie", "trains"), entry -> true);
         builder.pop();
       builder.pop();
   }

```

Now it is time to register your config file so that Forge can create and read the config file. Doing do, you simply call `ModLoadingContext.get().registerConfig` and pass in, the `ModConfig.Type`, the `GENERAL_SPEC` from your config file, and the name of the config file (make sure you include `.toml` as well. Like so: `ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfig.GENERAL_SPEC, "modconfig.toml");`

NOTE: Forge will only update the values of your config fields in code after the registry events are finished. Therefore, only attempt to read the config values after the registry events are completed. (FMLCommonSetupEvent and later is safe)

The ModConfig.Type determines where your config files goes and its behavior. While COMMON is generally used the most, the other config types do have specific uses. A simple summary is: ModConfig.Type.COMMON - Exists in the config folder above the mods folder and will apply to all worlds created. (Works for both client and servers) ModConfig.Type.CLIENT - Same as COMMON except the config file is only ever loaded on the client. Never on server. ModConfig.Type.SERVER - Exists only in a world's own config folder ona per-world basis. This is read on both server and on single player as well.

If you are going to have many config files for organization, you make want to put them into a specific folder for your mod within the config folder. Such as `configs/modid/blocks.toml` and `configs/modid/entities.toml` However, you would need to make that new folder first as Forge will not do it for you. Example: ```java FileUtils.getOrCreateDirectory(FMLPaths.CONFIGDIR.get().resolve("modid"), "modid"); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModIdConfigs.GENERAL_SPEC, "modid/blocks.toml"); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModIdConfigs.GENERAL_SPEC, "modid/entities.toml"); ```

Now your configs are setup, you know a decent chunk of how you can utilize Forge configs, and you are ready to go!