Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Monitoring changes to options for any reason is simple, thanks to the convenient methods provided by OneConfig. You can use them like so:
Easy enough, eh? But what if we want to know the new value at the time of the change?
You can use addDependency
to fine-tune the display status of your options based on your own conditions or other options. By default, simply using addDependency
and passing the options of your choosing will cause the dependant to be disabled rather than hidden.
hideIf
will ALWAYS completely hide the option passed to it based on the condition(s) provided as opposed to having to pick a display status.
To create your config, you'll first need to create a new class that extends OneConfig's Config
class, like so:
KtConfig provides additional functionality which makes it easier to create type-safe options in Kotlin with a much more readable and serviceable syntax.
Easy, right? Now, you'll need to provide it with some info via it's constructor, which takes your config's name, category, file name and some other relating data.
The filename you pass to OneConfig is what the file will be named inside of the user's OneConfig settings profile, f.ex .minecraft/config/OneConfig/profiles/example_config.json
.
Simple as that!
There are various different ways to initialize your config, but here are the way we recommend:
If you are on Java, add an INSTANCE
field to your config. This is where you will access your dedicated object of your config for non-static methods, such as save
.
If you are on Kotlin and you have not already, make your config class an object
. This makes your class a singleton, which essentially will create the INSTANCE
field in Java for you, and make accessing it via Kotlin syntax easier.
Now, all you need to do is initialize your config when the game first launches with your mod, via the preload
method. This can be done using your mod loader's standard means of initializing your mod at game launch, or alternatively, by using OneConfig's events system, using the InitializationEvent
.
Welcome to the OneConfig documentation for developers. If you're confused about how to integrate your mod with OneConfig, or just what something does, there's a good chance the answer is here.
The OneConfig Docs are licensed under the GNU Free Documentation License, version 1.3 or later.
How to add OneConfig to your mod
This is NOT a guide on how to start with modding or set up a modding template. There is documentation for every version of Minecraft that we support on how to set up a mod on their loader.
multi-version
All OneConfig-supported versions (1.8.9-Latest, Fabric/Forge)
You can always clone this branch and remove all but a single version, in case you want to tackle multiversion later.
legacy-forge
1.8.9 Forge
legacy-fabric
1.8.9 Fabric
modern-fabric
Latest Fabric
modern-forge
Latest Forge
kotlin-[branch]
N/A
Each branch has a Kotlin version.
If you don't want to use our mod template, or wish to include OneConfig in one of your new or existing mods, add this to your build.gradle(.kts)
.
OneConfig's functionality is split into several modules for ease of use and to improve the developer experience. When making a mod using OneConfig, you will need to individually select modules you will be utilizing within your mod in order to gain access to their functionality, and the platform / Minecraft version-specific implementation of OneConfig.
commands
The tree based command system used in OneConfig.
config
The tree based configuration system used in OneConfig.
config-impl
The default implementation of the configuration system used in OneConfig.
events
The event system used in OneConfig.
hud
The HUD system used in OneConfig.
internal
OneConfig's UI implementation.
ui
The UI system used in OneConfig.
utils
Various utilities used in OneConfig.
Keep in mind though, that these docs aren't perfect, so if something is wrong, feel free to , before we even notice.
If you encounter any errors or bugs in OneConfig, feel free to or If you're still stuck, join our server and create a ticket!
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3, or any later version published by the Free Software Foundation; with the Invariant Sections just being "Welcome" with no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "".
For Forge 1.8.9 and 1.12.2:
For Forge (modern):
For Fabric:
For NeoForge:
From there, instead of using the default templates of those loaders, you would use the .
If you're just starting out or need more advanced features like multiple versions, we highly recommend looking at our . When cloning the example mod, please choose from one of the following branches:
While you’re here, we recommend using , which automatically configures everything in your project for you, including OneConfig. DGT is included in our example mod template.
It also provides several smaller utilities for things such as authenticating your Minecraft/Microsoft account in the developer environment via or setting up your own Forge coremod.
OneConfig offers several different kinds of options for several different data types. Expand this page in the sidebar to view them all.
GNU Free Documentation License version 1.3
Below you can find a copy of the license and its terms for this documentation:
OneConfig has it's own custom event system, which can either be callback- or subscriber-based depending on your preferences. It provides several default events relating to basic OneConfig functionality and Minecraft-relating functionality.
It is preferred to use callback-based events for code quality, maintainability and speed.
If you have used the , you are likely more familiar with callback-based events. If you have worked with or , you are likely more familiar with subscriber-based events.
From here, if you want to do something when the command is run on it's own (f.ex /examplemod
), you can use the runs
method to define what is executed, like so:
Both the object which command
and runs
returns have a description
method which allow you to describe what happens when you execute that command or subcommand, it is recommended to use this where possible.
Finally, to register your command, you can simply use CommandManager#registerCommand
like so:
In order to create a command, you need to annotate a class with the @Command
annotation and provide it with the data required for users to interact with it (such as a name).
The values you provide to the annotation here are what the user types into the chat input to execute your command, such as /examplemod
To start, you'll obviously need to apply your starting annotation on a class, like so:
From here, you can add your main execution point! This method is executed when the user simply runs your command with no arguments or subcommand, like /examplemod
When the user executes any of the provided command names, "Hello, OneConfig!" will be printed out to the console / log file.
Now that you know how to create your command, and allow users to run it on it's own, let's take a look at allowing the user to input data.
Let's say we want to take in a name to greet someone in the console. We'd need the user to provide a string.
In the above example, we take a non-optional parameter called "Name", which we can then use to print out a greeting in the console.
OneConfig provides default parsers for all of the basic primitive types and very few custom types, such as Minecraft's GameProfile
, meaning that you'll need to provide your own parser for your own data objects.
So, let's say we have en enum type:
And we want the user to be able to select one of it's values. For this, we will need to create a custom ArgumentParser
.
So... What's going on here?!
First, in our parse
method, we're taking our arg
value and converting it to full uppercase to conform to enum naming conventions, then trying to find a value matching that name inside of ExampleEnum
.
Then, we implement autocompletion in getAutoCompletions
by checking the current input against all possible values in the enum. This is entirely optional, we can simply return null to opt out of autocomplete for whatever reason.
Lastly, we provide our ArgumentParser
with the definitive type of our custom object so that OneConfig's internals can determine when and where our parser needs to be utilized.
Now, when we create a command with ExampleEnum
as one of the parameter types, a user will be able to input any of the names in our enum and our command's execution point will receive that enum! Nifty, huh?
When you've got multiple functions under a single base command name, you're going to want to separate them into multiple subcommands. Luckily, it's as easy as creating more methods and annotating them with the very same annotation you used to create your base command:
Now, instead of your users needing to type /examplemod <NAME>
in the chat to greet someone in their console, they will be required to type /examplemod greet <NAME>
or /examplemod grt <NAME>
, as define by our subcommand.
To get started with OneConfig's tree-based (-style) command system, you'll need to get started by creating a CommandBuilder:
Getting started with OneConfig's callback-based events system is familiar, easy to learn and fast. If you've worked with FabricMC or QuiltMC before, you'll already be familiar with how these function.
Registering a listener is as simple as defining the class of the event you'd like to listen to, and providing a callback to be executed whenever that event is dispatched. This can be done via OneConfig's EventManager
, like so:
And that's it! Now, from this example, you'll be listening to the TickEvent.Start
event, and every time a new game tick starts, it will print "Tick tick tick!"
so long as our setupEvents
method/function is executed at least once in it's lifetime.
There is also a Kotlin DSL for an improved developer experience with event listeners:
There is a small set of basic, yet useful, networking utilities for things such as obtaining a string from a URL, downloading a file, etc.
It is recommended to use the name of your mod as the first half of your user agent, and the version as the second half.
Otherwise, you can simply call getString
using a URL to use the default OneConfig user agent, a timeout of 5000 milliseconds (5 seconds) and no caching.
Again, similarly to getString
, you can simply call this method with only the URL and path of the downloaded file.
The default implementation of Clipboard
uses the natives provided by Copycat. Calling the getInstance
method will automatically load the natives should it need to.
By default, ClipboardImage
on it's own is simply two int
s for the width
x height
, and an array of bytes for the raw image data. Thus meaning, that should you want to make use of it in any meaningful way, you'll need to convert it to another type for another library OR handle the raw bytes on your own. Thankfully, Copycat provides a means of converting to and from the Java AWT types for you, which you can find below.
This works vice-versa too!
OneConfig provides a single, ease-to-use method for obtaining the checksum of a file at a given path.
All of the custom data types contained within PlayerInfo
come from the library.
All of the custom data types contained within PartyInfo
come from the library.
All of the custom data types contained within Location
come from the library.
OneConfig no longer provides in-house utilities for managing the user's clipboard; however, we do include , which uses native code to bypass any issues brought on by certain operating systems (such as macOS disallowing headless apps from using the AWT clipboard API).
The Platform
class in OneConfig's utils
module is a means to provide several methods which will serve the same function regardless of what Minecraft version or mod loader is currently being used by the player. It serves several general purpose, smaller platform utilities such a localization, mod loader, OpenGL, etc utilities.
LoaderPlatform#getMinecraftVersion
(or Platform.loader().getMinecraftVersion()
) returns a 0-padded representation of the current Minecraft version, f.ex: 11605
or 10809
which represent 1.16.5 and 1.8.9 respectively.
LoaderPlatform#getLoader
(or Platform.loader().getLoader()
) returns the current mod loader, represented by the Loaders
enum, which contains FORGE
and FABRIC
.
LoaderPlatform#isDevelopmentEnvironment
(or Platform.loader().isDevelopmentEnvironment()
) can be used to check if the player is currently inside of a developer environment.
LoaderPlatform#isModLoaded
(or Platform.loader().isModLoaded(String)
) returns a boolean for if a mod with the given ID is currently loaded.
LoaderPlatform#getLoadedMods
(or Platform.loader().getLoadedMods()
) returns a list of ActiveMod
instances, all containing information such as a mod's name, ID, version and where it was loaded from (it's source).
PlayerPlatform#inMultiplayer
(or Platform.player().inMultiplayer()
) returns a boolean for if the player is currently connected to a multiplayer server or LAN world.
PlayerPlatform#inMultiplayer
(or Platform.player().inMultiplayer()
) returns a boolean for if the player is currently connected to a multiplayer server or LAN world.
OneConfig V0 had a system in which you would add a new VigilanceMigrator(...)
to your config's super constructor call in order to tell it where to find your old Vigilance config. Now, in OneConfig V1, we are prioritizing allowing developers to migrate from more other config systems independently.
You can now replace your VigilanceMigrator
instantiation with a call to loadFrom
in your constructor, passing the path to your old config to it.
You can also replace all @VigilanceName
annotations with the new @PreviousNames
annotation, in which you can simply pass the full path (category + subcategory + name) to your old option, f.ex: "oldCategory.oldSubcategory.oldName1", "oldCategory.oldName2", ...
OneConfig V1 is now available to all developers, with some conditions:
Not everything has been documented just yet...
Currently, V1 will not work on modern versions due to an issue with LWJGL natives. But it compiles!
Expect bugs with OneConfig V1 itself.
Below are screenshots of the new GUI. Yes, these are concept designs, but it's basically been implemented 1:1 and I'm way too lazy to take actual screenshots lol
You should be able to do a find and replace with import <old package name>
. Go in opposite order from this list if you want to do a full search and replace.
All the ported versions should be in the "twoconfig" branch (EXCEPT EvergreenHUD, that work is in the "rewrite" branch).
This is in NO WAY a complete guide as of yet. if you find any discrepancies.
Please follow the guide for this.
This is in NO WAY a complete guide as of yet. if you find any discrepancies.
We recommend checking out our mods, which have somewhat already been ported to V1 (59%). Good examples are , , and . Here is a periodically updated list of our ported mods:
Getting started with OneConfig's subscriber-based events system is easy and straightforward! If you've worked with MinecraftForge or NeoForge before, you'll be more than familiar with how these function.
In order for your subscriber methods to execute when an event is dispatched, you'll need to register their containing instance as an event listener. This can be done via an instance of EventManager
, typically the statically provided INSTANCE
:
Now that your instance is registered as an event listener, you can define your subscriber methods for the events which you want to listen for dispatches of. This can be done by defining those events as parameters for a method/function then annotating that same method/function with @Subscribe
.
And there you have it! This instance of our ExampleListener
now receives all dispatched instances of TickEvent.Start
as long as our run
method/function is executed at least once in it's lifetime.
You can unsafely (exceptionally) parse JSON from a string using JsonUtils#parse(String)
, like so:
If incorrect JSON syntax is passed to this method, GSON will throw a JsonSyntaxException
JsonUtils#parseOrNull
will automatically catch any exceptions thrown by GSON's parser and return the resulting JsonElement
or null if a parsing error was thrown. It can be used like so:
An additional, third method is present for the purpose of running a callback if parsing succeeds on the string given.