Creating a brand-new config system based on Fzzy Config? Let's get started! This guide will walk through the basic steps needed to get your config up and running.
Steps
- Development of Config layout
- Config class(es) creation
- Config Registration
- Polish
- Integration into the Mod
1. Development of a Config Layout ⤴
Before you get into your Config implementation, figure out the layout you want (see article link below). This layout will determine how the configs are laid out visually, the user experience of navigating your settings, and how you interact with the config internally.
Heads up!
This step is so important to all future uses of the config that I hesitate to say that there is a "quick and dirty" way to do it. Nevertheless, some mods only need a very simple config, so a very simple layout will do.
2. Config Creation ⤴
With your layout in mind, create some config classes and fill them with the settings you need. Configs extend the base class Config
.
- Extend
Config
, provide an Identifier, and any custom folder(s) as needed. - Fill in your empty class with settings. Settings have the following considerations:
- fields/properties need to be non-final, non-static, and public
- check out Validation for more powerful setting configuration and choice-restriction options.
Heads up!
If you use the IgnoreVisibility
annotation, you can set the visibility less than public (private, protected, etc).
Heads up!
For Kotlin users, configs cannot be object
, as they need to be instanced. You can have a separate Config object used internally throughout the mod that references an instance of the config class implementation
public class MyConfig extends Config {public MyConfig() {super(Identifier.of(MOD_ID, "my_config"));}public double bareDouble = 5.0; // A double without validation. It will still have basic type-validation backing it internally.public boolean booleanThing = false; // most primitive types and a wide array of other types are supported by background validation. See Validation for details.public ValidatedDouble validatedDouble = new ValidatedDouble(5.0, 10.0, 0.0); //this field has defined validation, error correction, and will restrict user inputs to doubles between 0 and 10.public MySection mySection = new MySection(); // a section of the config with its own validated fields and other sections as applicable. This will appear in-game as a separate screen "layer" with a breadcrumb leading back to the parent screen.public static class MySection extends ConfigSection { // a Config Section. Self-serializable. Of course it doesn't have to be defined inside of it's parent class, but it may be convenientpublic MySection() {super();}public ValidatedBoolean sectionBoolean = ValidatedBoolean(true); //booleans can have defined validation, but it's not really necessarypublic ValidatedIdentifierMap<Double> sectionMap = ValidatedIdentifierMap( //validation exists for common collections too, maps, lists, sets, and so onnew LinkedHashMap(), //empty default mapValidatedIdentifier.ofTag(Registries.ITEM.getId(Items.IRON_AXE), ItemTags.AXES), // the keys in this map can only be from the AXES tagnew ValidatedDouble(1.0, 1.0, 0.0) //map values are double restricted between 0.0 and 1.0);}}
3. Config Registration ⤴
Configs are accessed via an INSTANCE
pattern. Access in this manner, with the API calls for registration and loading described below, prevents "too-early" access to a config that hasn't been populated with live data.
registerAndLoadConfig
. The API call for registering and loading a config from file It will also automatically create the file if none exists. Select yourRegisterType
based on the user needs for the config settingsBOTH
- Default, will have a GUI client side, and will also auto-sync between servers and clients.CLIENT
- Will only have GUI functionality, no syncing to/from servers.SERVER
- No GUI, only auto-syncing between servers and clients (Not Recommended, the only way to edit these configs is directly the .toml).
class Configs {//instance of your config loaded from file and automatically registered to the SyncedConfigRegistry and ClientConfigRegistry using the getId() method//ConfigApiJava can come in handy to avoid pernicious compiler errors depending on your IDE and gradle setup.public static MyConfig myConfig = ConfigApiJava.registerAndLoadConfig(MyConfig::new);//adding the registerType, you can register a config as client-only. No syncing will occur. Useful for client-only mods.public static MyConfig myClientOnlyConfig = ConfigApiJava.registerAndLoadConfig(MyConfig::new, RegisterType.CLIENT);//adding the registerType, you can register a config as sync-only. Their won't be any client-side GUI functionality, so the config will only be editable from the file itself, but it will auto-sync with clients.public static MyConfig mySyncedOnlyConfig = ConfigApiJava.registerAndLoadConfig(MyConfig::new, RegisterType.SERVER);//Init function would be called in ModInitializer or some other entrypoint. Not strictly necessary if loading on-reference is ok.public static void init() {}}
4. Polish ⤴
Your basic config is complete! But the features are only just beginning. Read on to take your config to the next level! Or don't. Fzzy Config will work for you either way :).
Validation
Already mentioned in step 2, Fzzy Config comes with a powerful suite of validation tools. Among many other features, these tools:
- Validate inputs and correct improper inputs
- Provide input restrictions
- Suggest inputs to users
Check out the options at:
Annotations
Fzzy Config has a variety of annotations that provide secondary functions a config author might have need of:
- Version Control
- Annotation-based validation for primitives
- Comments
- Server config permission control
- Various flags; client only, restart-triggering, and so on.
For the full breakdown of annotations available, check out:
Translation
Most aspects of a config are automatically translatable. You don't have to translate anything, but it's strongly recommended. If you don't, Fzzy Config will do its best to generate human-readable names from the class and field names of the configs themselves.
To properly translate your column head on over to:
5. Integration into your Mod ⤴
You've got a shiny, polished up config! How do you use it?
- Simply call the fields as you normally would.
ValidatedField
instances are suppliers. Simply add.get()
to the end.
double myConfigDouble = Configs.myConfig.bareDouble; //plain fields are just plain fields. access them like normal!boolean myConfigSectionValidated = Configs.myConfig.mySection.sectionBoolean.get(); //defined validation wraps your values in a Supplier.