diff --git a/docs/gettingstarted/index.md b/docs/gettingstarted/index.md index e3f8a5da..eb2f1ec4 100644 --- a/docs/gettingstarted/index.md +++ b/docs/gettingstarted/index.md @@ -1,127 +1,60 @@ -# Getting Started with Forge +# Getting Started with NeoForge -:::caution -Please note that this documentation may not be up to date considering the recent creation of NeoForged. - -Until NeoForged releases its first version, you should refer to Forge documentation. The Forge documentation for 1.20 has been archived here. -::: - -If you have never made a Forge mod before, this section will provide the minimum amount of information needed to setup a Forge development environment. The rest of the documentation is about where to go from here. +This section includes information about how to set up a NeoForge workspace, and how to run and test your mod. ## Prerequisites -- An installation of the Java 17 Development Kit (JDK) and 64-bit Java Virtual Machine (JVM). Forge recommends and officially supports [Eclipse Temurin][jdk]. +- Familiarity with the Java programming language, specifically its object-oriented, polymorphic, generic, and functional features. +- An installation of the Java 17 Development Kit (JDK) and 64-bit Java Virtual Machine (JVM). NeoForge recommends and officially supports the [Microsoft builds of OpenJDK][jdk], but any other JDK should work as well. :::caution - -Make sure you are using a 64-bit JVM. One way of checking is to run `java -version` in a terminal. Using a 32-bit JVM will cause some problems when using [ForgeGradle]. - +Make sure you are using a 64-bit JVM. One way of checking is to run `java -version` in a terminal. Issues may arise when using a 32-bit JVM, due to 32-bit JVMs running out of support for a lot of things. ::: -- Familiarity with an Integrated Development Environment (IDE). - - It is recommended to use an IDE with Gradle integration. - -## From Zero to Modding - -1. Download the Mod Developer Kit (MDK) from the [Forge file site][files] by clicking 'Mdk' followed by the 'Skip' button in the top right after waiting for a period of time. It is recommended to download the latest version of Forge whenever possible. -2. Extract the downloaded MDK into an empty directory. This will be your mod's directory, which should now contain some gradle files and a `src` subdirectory containing the example mod. +- Familiarity with an Integrated Development Environment (IDE) of your choice. + - NeoForge officially supports [IntelliJ IDEA][intellij] and [Eclipse][eclipse], both of which have integrated Gradle support. However, any IDE can be used, ranging from Netbeans or Visual Studio Code to Vim or Emacs. +- Familiarity with [Git][git] and [GitHub][github]. This is technically not required, but it will make your life a lot easier. -:::info +## Setting Up the Workspace -A number of files can be reused across different mods. These files are: - -- the `gradle` subdirectory -- `build.gradle` -- `gradlew` -- `gradlew.bat` -- `settings.gradle` - -The `src` subdirectory does not need to be copied across workspaces; however, you may need to refresh the Gradle project if the java (`src/main/java`) and resource (`src/main/resources`) are created later. -::: - -3. Open your selected IDE: - - Forge only explicitly supports development on Eclipse and IntelliJ IDEA, but there are additional run configurations for Visual Studio Code. Regardless, any environment, from Apache NetBeans to Vim / Emacs, can be used. - - Eclipse and IntelliJ IDEA's Gradle integration, both installed and enabled by default, will handle the rest of the initial workspace setup on import or open. This includes downloading the necessary packages from Mojang, MinecraftForge, etc. The 'Gradle for Java' plugin is needed for Visual Studio Code to do the same. - - Gradle will need to be invoked to re-evaluate the project for almost all changes to its associated files (e.g., `build.gradle`, `settings.gradle`, etc.). Some IDEs come with 'Refresh' buttons to do this; however, it can be done through the terminal via `gradlew`. -4. Generate run configurations for your selected IDE: - - **Eclipse**: Run the `genEclipseRuns` task. - - **IntelliJ IDEA**: Run the `genIntellijRuns` task. If a "module not specified" error occurs, set the [`ideaModule` property][config] to your 'main' module (typically `${project.name}.main`). - - **Visual Studio Code**: Run the `getVSCodeRuns` task. - - **Other IDEs**: You can run the configurations directly using `gradle run*` (e.g., `runClient`, `runServer`, `runData`, `runGameTestServer`). These can also be used with the supported IDEs. +- Open the [Mod Developer Kit (MDK)][mdk] GitHub repository, click "Use this template" and clone the newly-created repository to your local machine. + - If you do not want to use GitHub, or if you want to get the template for an older commit or a non-default branch (which would be the case e.g. for older versions), you can also download the ZIP of the repository (under Code -> Download ZIP) and extract it. +- Open your IDE and import the Gradle project. Eclipse and IntelliJ IDEA will do this automatically for you. If you have an IDE that does not do this, you can also do it via the `gradlew` terminal command. + - When doing this for the first time, Gradle will download all dependencies of NeoForge, including Minecraft itself, and decompile them. This can take a fair amount of time (up to an hour, depending on your hardware and network strength). + - Whenever you make a change to the Gradle files, the Gradle changes will need to be reloaded, either through the "Reload Gradle" button in your IDE, or again through the `gradlew` terminal command. ## Customizing Your Mod Information -Edit the `build.gradle` file to customize how your mod is built (e.g., file name, artifact version, etc.). - -:::danger -Do **not** edit the `settings.gradle` unless you know what you are doing. The file specifies the repository that [ForgeGradle] is uploaded to. -::: - -### Recommended `build.gradle` Customizations +Many of the basic properties of your mod can be changed in the `gradle.properties` file. This includes basic things like the mod name or the mod version. For more information, see the comments in the `gradle.properties` file, or see [the documentation of the `gradle.properties` file][properties]. -#### Mod Id Replacement +If you want to modify the build process beyond that, you can edit the `build.gradle` file. NeoGradle, the Gradle plugin for NeoForge, provides several configuration options, a few of which are explained by comments in the `build.gradle` files. For full documentation, see the [NeoGradle documentation][neogradle]. -Replace all occurrences of `examplemod`, including [`mods.toml` and the main mod file][modfiles] with the mod id of your mod. This also includes changing the name of the file you build by setting `base.archivesName` (this is typically set to your mod id). - -```gradle -// In some build.gradle -base.archivesName = 'mymod' -``` - -#### Group Id - -The `group` property should be set to your [top-level package][packaging], which should either be a domain you own or your email address: - -| Type | Value | Top-Level Package | -| :-------: | :---------------: | :------------------ | -| Domain | example.com | `com.example` | -| Subdomain | example.github.io | `io.github.example` | -| Email | example@gmail.com | `com.gmail.example` | - -```gradle -// In some build.gradle -group = 'com.example' -``` - -The packages within your java source (`src/main/java`) should also now conform to this structure, with an inner package representing the mod id: - -```text -com -- example (top-level package specified in group property) - - mymod (the mod id) - - MyMod.java (renamed ExampleMod.java) -``` +:::caution +Only edit the `build.gradle` and `settings.gradle` files if you know what you are doing. All basic properties can be set via `gradle.properties`. +::: -#### Version +## Building and Testing Your Mod -Set the `version` property to the current version of your mod. We recommend using a [variation of Maven versioning][mvnver]. +To build your mod, run `gradlew build`. This will output a file in `build/libs` with the name `-.jar`. `` and `` are properties set by the `build.gradle` and default to the `mod_id` and `mod_version` values in the `gradle.properties` file, respectively; this can be changed in the `build.gradle` if desired. The resulting JAR file can then be placed in the `mods` folder of a NeoForge-enabled Minecraft setup, or uploaded to a mod distribution platform. -```gradle -// In some build.gradle -version = '1.20-1.0.0.0' -``` +To run your mod in a test environment, you can either use the generated run configurations or use the associated tasks (e.g. `gradlew runClient`). This will launch Minecraft from the corresponding runs directory (e.g. `runs/client` or `runs/server`), along with any source sets specified. The default MDK includes the `main` source set, so any code written in `src/main/java` will be applied. -### Additional Configurations +### Server Testing -Additional configurations can be found on the [ForgeGradle] docs. +If you are running a dedicated server, whether through the run configuration or `gradlew runServer`, the server will shut down immediately. You will need to accept the Minecraft EULA by editing the `eula.txt` file in the run directory. -## Building and Testing Your Mod - -1. To build your mod, run `gradlew build`. This will output a file in `build/libs` with the name `[archivesBaseName]-[version].jar`, by default. This file can be placed in the `mods` folder of a Forge-enabled Minecraft setup or distributed. -1. To run your mod in a test environment, you can either use the generated run configurations or use the associated tasks (e.g. `gradlew runClient`). This will launch Minecraft from the run directory (default 'run') along with any source sets specified. The default MDK includes the `main` source set, so any code written in `src/main/java` will be applied. -1. If you are running a dedicated server, whether through the run configuration or `gradlew runServer`, the server will initially shut down immediately. You will need to accept the Minecraft EULA by editing the `eula.txt` file in the run directory. Once accepted, the server will load, which can then be accessed via a direct connect to `localhost`. +Once accepted, the server will load and become available under `localhost` (or `127.0.0.1` by default). However, you will still not able to join, because the server will be put into online mode by default, which requires authentication (that the Dev player does not have). To fix this, stop your server again and set the `online-mode` property in the `server.properties` file to `false`. Now, start your server, and you should be able to connect. :::tip - -You should always test your mod in a dedicated server environment. This includes [client-only mods][client] as they should not do anything when loaded on the server. - +You should always test your mod in a dedicated server environment. This includes [client-only mods][client], as these should not do anything when loaded on the server. ::: -[jdk]: https://adoptium.net/temurin/releases?version=17 "Eclipse Temurin 17 Prebuilt Binaries" -[ForgeGradle]: https://docs.neoforged.net/neogradle/docs/ -[files]: https://files.minecraftforge.net "Forge Files distribution site" -[config]: https://docs.neoforged.net/neogradle/docs/configuration/runs -[modfiles]: ./modfiles.md -[packaging]: ./structuring.md#packaging -[mvnver]: ./versioning.md [client]: ../concepts/sides.md#writing-one-sided-mods +[eclipse]: https://www.eclipse.org/downloads/ +[git]: https://www.git-scm.com/ +[github]: https://github.com/ +[intellij]: https://www.jetbrains.com/idea/ +[jdk]: https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-17 +[mdk]: https://github.com/neoforged/MDK +[neogradle]: https://docs.neoforged.net/neogradle/docs/ +[properties]: modfiles.md#gradleproperties diff --git a/docs/gettingstarted/modfiles.md b/docs/gettingstarted/modfiles.md index aabf0611..16a46d38 100644 --- a/docs/gettingstarted/modfiles.md +++ b/docs/gettingstarted/modfiles.md @@ -1,70 +1,80 @@ -Mod Files -========= +# Mod Files The mod files are responsible for determining what mods are packaged into your JAR, what information to display within the 'Mods' menu, and how your mod should be loaded in the game. -mods.toml ---------- +## gradle.properties -The `mods.toml` file defines the metadata of your mod(s). It also contains additional information that is displayed within the 'Mods' menu and how your mod(s) should be loaded into the game. +The `gradle.properties` file holds various common properties of your mod, such as the mod id or mod version. During building, Gradle reads the values in these files and inlines them in various places, such as the [mods.toml][modstoml] file. This way, you only need to change values in one place, and they are then applied everywhere for you. -The file uses the [Tom's Obvious Minimal Language, or TOML][toml], format. The file must be stored under the `META-INF` folder in the resource directory of the source set you are using (`src/main/resources/META-INF/mods.toml` for the `main` source set). A `mods.toml` file may look something like this: +Most values are also explained as comments in [the MDK's `gradle.properties` file]. -```toml -modLoader="javafml" -loaderVersion="[46,)" +| Property | Description | Example | +|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------| +| `org.gradle.jvmargs` | Allows you to pass extra JVM arguments to Gradle. Most commonly, this is used to assign more/less memory to Gradle. Note that this is for Gradle itself, not Minecraft. | `org.gradle.jvmargs=-Xmx3G` | +| `org.gradle.daemon` | Whether Gradle should use the daemon when building. | `org.gradle.daemon=false` | +| `org.gradle.debug` | Whether Gradle is set to debug mode. Debug mode mainly means more Gradle log output. Note that this is for Gradle itself, not Minecraft. | `org.gradle.debug=false` | +| `minecraft_version` | The Minecraft version you are modding on. Must match with `neo_version`. | `minecraft_version=1.20.2` | +| `minecraft_version_range` | The Minecraft version range this mod can use, as a [Maven Version Range][mvr]. Note that [snapshots, pre-releases and release candidates][mcversioning] are not guaranteed to sort properly, as they do not follow maven versioning. | `minecraft_version_range=[1.20.2,1.20.3)` | +| `neo_version` | The NeoForge version you are modding on. Must match with `minecraft_version`. See [NeoForge Versioning][neoversioning] for more information on how NeoForge versioning works. | `minecraft_version=1.20.2` | +| `neo_version_range` | The NeoForge version range this mod can use, as a [Maven Version Range][mvr]. | `minecraft_version_range=[1.20.2,1.20.3)` | +| `loader_version_range` | The version range of the mod loader this mod can use, as a [Maven Version Range][mvr]. Note that the loader versioning is decoupled from NeoForge versioning. | `loader_version_range=[1,)` | +| `mod_id` | The id of your mod. This should be something unique and memorable, as having two mods with the same id will prevent the game from loading. The mod id shows up in a lot of places, for example as the namespace for all your registered things, or as the namespace for your resource and data packs. | `mod_id=examplemod` | +| `mod_name` | The human-readable display name of your mod. By default, this can only be seen in the mod list, however, mods such as [JEI][jei] prominently display mod names in item tooltips as well. | `mod_name=Example Mod` | +| `mod_license` | The license your mod is provided under. It is suggested that this is set to the [SPDX identifier][spdx] you are using and/or a link to the license. You can visit https://choosealicense.com/ to help pick the license you want to use. | `mod_license=MIT` | +| `mod_version` | The version of your mod, shown in the mod list. See [the page on Versioning][versioning] for more information. | `mod_version=1.0` | +| `mod_group_id` | See [The Group ID][group]. | `mod_group_id=com.example.examplemod` | +| `mod_authors` | The authors of the mod, shown in the mod list. | `mod_authors=ExampleModder` | +| `mod_description` | The description of the mod, as a multiline string, shown in the mod list. Newline characters (`\n`) can be used and will be replaced properly. | `mod_authors=Example mod description.` | +| `pack_format_number` | The version number of your mod's data and resource pack. Mojang bumps this without something that could be considered a consistent scheme, so it's best to just look up what the current number is. As of Minecraft 1.20.2, the pack version is `18`. | `pack_version_number=18` | -license="All Rights Reserved" -issueTrackerURL="https://github.com/MinecraftForge/MinecraftForge/issues" -showAsResourcePack=false +### The Group ID -[[mods]] - modId="examplemod" - version="1.0.0.0" - displayName="Example Mod" - updateJSONURL="https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json" - displayURL="https://minecraftforge.net" - logoFile="logo.png" - credits="I'd like to thank my mother and father." - authors="Author" - description=''' - Lets you craft dirt into diamonds. This is a traditional mod that has existed for eons. It is ancient. The holy Notch created it. Jeb rainbowfied it. Dinnerbone made it upside down. Etc. - ''' - displayTest="MATCH_VERSION" - -[[dependencies.examplemod]] - modId="forge" - mandatory=true - versionRange="[46,)" - ordering="NONE" - side="BOTH" - -[[dependencies.examplemod]] - modId="minecraft" - mandatory=true - versionRange="[1.20]" - ordering="NONE" - side="BOTH" +While the `group` property in the `build.gradle` is only necessary if you plan to publish your mod to a maven, it is considered good practice to always properly set this. This is done for you through the `gradle.properties`'s `mod_group_id` property. + +The group id should be set to your top-level package. See [Packaging][packaging] for more information. + +```text +// In your gradle.properties file +mod_group_id=com.example ``` -`mods.toml` is broken into three parts: the non-mod-specific properties, which are linked to the mod file; the mod properties, with a section for each mod; and the dependency configurations, with a section for each mod's or mods' dependencies. Each of the properties associated with the `mods.toml` file will be explained below, where `required` means that a value must be specified or an exception will be thrown. +The packages within your java source (`src/main/java`) should also now conform to this structure, with an inner package representing the mod id: + +```text +com +- example (top-level package specified in group property) + - mymod (the mod id) + - MyMod.java (renamed ExampleMod.java) +``` + +## mods.toml + +The `mods.toml` file, located at `src/main/resources/META-INF/mods.toml`, is a file in [TOML][toml] format that defines the metadata of your mod(s). It also contains additional information on how your mod(s) should be loaded into the game, as well as display information that is displayed within the 'Mods' menu. The [`mods.toml` file provided by the MDK][mdkmodstoml] contains comments explaining every entry, they will be explained here in more detail. + +The `mods.toml` can be separated into three parts: the non-mod-specific properties, which are linked to the mod file; the mod properties, with a section for each mod; and the dependency configurations, with a section for each mod's or mods' dependencies. Some of the properties associated with the `mods.toml` file are mandatory; mandatory properties require a value to be specified, otherwise an exception will be thrown. + +:::note +In the default MDK, Gradle replaces various properties in this file with the values specified in the `gradle.properties` file. For example, the line `license="${mod_license}"` means that the `license` field is replaced by the `mod_license` property from `gradle.properties`. Values that are replaced like this should be changed in the `gradle.properties` instead of changing them here. +::: ### Non-Mod-Specific Properties Non-mod-specific properties are properties associated with the JAR itself, indicating how to load the mod(s) and any additional global metadata. -Property | Type | Default | Description | Example -:--- | :---: | :---: | :---: | :--- -`modLoader` | string | **mandatory** | The language loader used by the mod(s). Can be used to support alternative language structures, such as Kotlin objects for the main file, or different methods of determining the entrypoint, such as an interface or method. Forge provides the Java loader `"javafml"` and low/no code loader `"lowcodefml"`. | `"javafml"` -`loaderVersion` | string | **mandatory** | The acceptable version range of the language loader, expressed as a [Maven Version Range][mvr]. For `javafml` and `lowcodefml`, the version is the major version of the Forge version. | `"[46,)"` -`license` | string | **mandatory** | The license the mod(s) in this JAR are provided under. It is suggested that this is set to the [SPDX identifier][spdx] you are using and/or a link to the license. You can visit https://choosealicense.com/ to help pick the license you want to use. | `"MIT"` -`showAsResourcePack` | boolean | `false` | When `true`, the mod(s)'s resources will be displayed as a separate resource pack on the 'Resource Packs' menu, rather than being combined with the 'Mod resources' pack. | `true` -`services` | array | `[]` | An array of services your mod **uses**. This is consumed as part of the created module for the mod from Forge's implementation of the Java Platform Module System. | `["net.minecraftforge.forgespi.language.IModLanguageProvider"]` -`properties` | table | `{}` | A table of substitution properties. This is used by `StringSubstitutor` to replace `${file.}` with its corresponding value. This is currently only used to replace the `version` in the [mod-specific properties][modsp]. | `{ "example" = "1.2.3" }` referenced by `${file.example}` -`issueTrackerURL` | string | *nothing* | A URL representing the place to report and track issues with the mod(s). | `"https://forums.minecraftforge.net/"` +| Property | Type | Default | Description | Example | +|:---------------------|:-------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------| +| `modLoader` | string | **mandatory** | The language loader used by the mod(s). Can be used to support alternative language structures, such as Kotlin objects for the main file, or different methods of determining the entrypoint, such as an interface or method. NeoForge provides the Java loader [`"javafml"`][javafml] and the lowcode/nocode loader [`"lowcodefml"`][lowcodefml]. | `modLoader="javafml"` | +| `loaderVersion` | string | **mandatory** | The acceptable version range of the language loader, expressed as a [Maven Version Range][mvr]. For `javafml` and `lowcodefml`, this is currently version `1`. | `loaderVersion="[1,)"` | +| `license` | string | **mandatory** | The license the mod(s) in this JAR are provided under. It is suggested that this is set to the [SPDX identifier][spdx] you are using and/or a link to the license. You can visit https://choosealicense.com/ to help pick the license you want to use. | `license="MIT"` | +| `showAsResourcePack` | boolean | `false` | When `true`, the mod(s)'s resources will be displayed as a separate resource pack on the 'Resource Packs' menu, rather than being combined with the 'Mod resources' pack. | `showAsResourcePack=true` | +| `services` | array | `[]` | An array of services your mod uses. This is consumed as part of the created module for the mod from NeoForge's implementation of the Java Platform Module System. | `services=["net.minecraftforge.forgespi.language.IModLanguageProvider"]` | +| `properties` | table | `{}` | A table of substitution properties. This is used by `StringSubstitutor` to replace `${file.}` with its corresponding value. | `properties={"example"="1.2.3"}` (can then be referenced by `${file.example}`) | +| `issueTrackerURL` | string | *nothing* | A URL representing the place to report and track issues with the mod(s). | `"https://github.com/neoforged/NeoForge/issues"` | :::note -The `services` property is functionally equivalent to specifying the [`uses` directive in a module][uses], which allows [*loading*][serviceload] a service of a given type. +The `services` property is functionally equivalent to specifying the [`uses` directive in a module][uses], which allows [loading a service of a given type][serviceload]. + +Alternatively, it can be defined in a service file inside the `src/main/resources/META-INF/services` folder, where the file name is the fully-qualified name of the service, and the file content is the name of the service to load (see also [this example from the AtlasViewer mod][atlasviewer]). ::: ### Mod-Specific Properties @@ -81,87 +91,98 @@ modId = "examplemod1" modId = "examplemod2" ``` -Property | Type | Default | Description | Example -:--- | :---: | :---: | :---: | :--- -`modId` | string | **mandatory** | The unique identifier representing this mod. The id must match `^[a-z][a-z0-9_]{1,63}$` (a string 2-64 characters; starts with a lowercase letter; made up of lowercase letters, numbers, or underscores). | `"examplemod"` -`namespace` | string | value of `modId` | An override namespace for the mod. The namespace much match `^[a-z][a-z0-9_.-]{1,63}$` (a string 2-64 characters; starts with a lowercase letter; made up of lowercase letters, numbers, underscores, dots, or dashes). Currently unused. | `"example"` -`version` | string | `"1"` | The version of the mod, preferably in a [variation of Maven versioning][mvnver]. When set to `${file.jarVersion}`, it will be replaced with the value of the `Implementation-Version` property in the JAR's manifest (displays as `0.0NONE` in a development environment). | `"1.20-1.0.0.0"` -`displayName` | string | value of `modId` | The pretty name of the mod. Used when representing the mod on a screen (e.g., mod list, mod mismatch). | `"Example Mod"` -`description` | string | `"MISSING DESCRIPTION"` | The description of the mod shown in the mod list screen. It is recommended to use a [multiline literal string][multiline]. | `"This is an example."` -`logoFile` | string | *nothing* | The name and extension of an image file used on the mods list screen. The logo must be in the root of the JAR or directly in the root of the source set (e.g., `src/main/resources` for the main source set). | `"example_logo.png"` -`logoBlur` | boolean | `true` | Whether to use `GL_LINEAR*` (true) or `GL_NEAREST*` (false) to render the `logoFile`. | `false` -`updateJSONURL` | string | *nothing* | A URL to a JSON used by the [update checker][update] to make sure the mod you are playing is the latest version. | `"https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json"` -`features` | table | `{}` | See '[features]'. | `{ java_version = "17" }` -`modproperties` | table | `{}` | A table of key/values associated with this mod. Currently unused by Forge, but is mainly for use by mods. | `{ example = "value" }` -`modUrl` | string | *nothing* | A URL to the download page of the mod. Currently unused. | `"https://files.minecraftforge.net/"` -`credits` | string | *nothing* | Credits and acknowledges for the mod shown on the mod list screen. | `"The person over here and there."` -`authors` | string | *nothing* | The authors of the mod shown on the mod list screen. | `"Example Person"` -`displayURL` | string | *nothing* | A URL to the display page of the mod shown on the mod list screen. | `"https://minecraftforge.net/"` -`displayTest` | string | `"MATCH_VERSION"` | See '[sides]'. | `"NONE"` +| Property | Type | Default | Description | Example | +|:----------------|:-------:|:---------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------| +| `modId` | string | **mandatory** | The unique identifier representing this mod. The id must match `^[a-z][a-z0-9_]{1,63}$` (a string 2-64 characters; starts with a lowercase letter; made up of lowercase letters, numbers, or underscores). | `modId="examplemod"` | +| `namespace` | string | value of `modId` | An override namespace for the mod. The namespace much match `^[a-z][a-z0-9_.-]{1,63}$` (a string 2-64 characters; starts with a lowercase letter; made up of lowercase letters, numbers, underscores, dots, or dashes). Currently unused. | `namespace="example"` | +| `version` | string | `"1"` | The version of the mod, preferably in a [variation of Maven versioning][versioning]. When set to `${file.jarVersion}`, it will be replaced with the value of the `Implementation-Version` property in the JAR's manifest (displays as `0.0NONE` in a development environment). | `version="1.20.2-1.0.0"` | +| `displayName` | string | value of `modId` | The display name of the mod. Used when representing the mod on a screen (e.g., mod list, mod mismatch). | `displayName="Example Mod"` | +| `description` | string | `'''MISSING DESCRIPTION'''` | The description of the mod shown in the mod list screen. It is recommended to use a [multiline literal string][multiline]. | `description='''This is an example.'''` | +| `logoFile` | string | *nothing* | The name and extension of an image file used on the mods list screen. The logo must be in the root of the JAR or directly in the root of the source set (e.g. `src/main/resources` for the main source set). | `logoFile="example_logo.png"` | +| `logoBlur` | boolean | `true` | Whether to use `GL_LINEAR*` (true) or `GL_NEAREST*` (false) to render the `logoFile`. In simpler terms, this means whether the logo should be blurred or not when trying to scale the logo. | `logoBlur=false` | +| `updateJSONURL` | string | *nothing* | A URL to a JSON used by the [update checker][update] to make sure the mod you are playing is the latest version. | `updateJSONURL="https://example.github.io/update_checker.json"` | +| `features` | table | `{}` | See [features]. | `features={java_version="[17,)"}` | +| `modproperties` | table | `{}` | A table of key/values associated with this mod. Unused by NeoForge, but is mainly for use by mods. | `modproperties={example="value"}` | +| `modUrl` | string | *nothing* | A URL to the download page of the mod. Currently unused. | `modUrl="https://neoforged.net/"` | +| `credits` | string | *nothing* | Credits and acknowledges for the mod shown on the mod list screen. | `credits="The person over here and there."` | +| `authors` | string | *nothing* | The authors of the mod shown on the mod list screen. | `authors="Example Person"` | +| `displayURL` | string | *nothing* | A URL to the display page of the mod shown on the mod list screen. | `displayURL="https://minecraftforge.net/"` | +| `displayTest` | string | `"MATCH_VERSION"` | See [sides]. | `displayTest="NONE"` | #### Features -The features system allows mods to demand that certain settings, software, or hardware are available when loading the system. When a feature is not satisfied, mod loading will fail, informing the user about the requirement. Currently, Forge provides the following features: +The features system allows mods to demand that certain settings, software, or hardware are available when loading the system. When a feature is not satisfied, mod loading will fail, informing the user about the requirement. Currently, NeoForge provides the following features: -Feature | Description | Example -:---: | :---: | :--- -`java_version` | The acceptable version range of the Java version, expressed as a [Maven Version Range][mvr]. This should be the supported version used by Minecraft. | `"[17,)"` +| Feature | Description | Example | +|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------| +| `java_version` | The acceptable version range of the Java version, expressed as a [Maven Version Range][mvr]. This should be the supported version used by Minecraft. | `features={java_version="[17,)"}` | +| `openGLVersion` | The acceptable version range of the OpenGL version, expressed as a [Maven Version Range][mvr]. Minecraft requires OpenGL 3.2 or newer. If you want to require a newer OpenGL version, you can do so here. | `features={openGLVersion="[4.6,)"}` | ### Dependency Configurations -Mods can specify their dependencies, which are checked by Forge before loading the mods. These configurations are created using the [array of tables][array] `[[dependencies.]]` where `modid` is the identifier of the mod the dependency is for. +Mods can specify their dependencies, which are checked by NeoForge before loading the mods. These configurations are created using the [array of tables][array] `[[dependencies.]]`, where `modid` is the identifier of the mod that consumes the dependency. -Property | Type | Default | Description | Example -:--- | :---: | :---: | :---: | :--- -`modId` | string | **mandatory** | The identifier of the mod added as a dependency. | `"example_library"` -`mandatory` | boolean | **mandatory** | Whether the game should crash when this dependency is not met. | `true` -`versionRange` | string | `""` | The acceptable version range of the language loader, expressed as a [Maven Version Range][mvr]. An empty string matches any version. | `"[1, 2)"` -`ordering` | string | `"NONE"` | Defines if the mod must load before (`"BEFORE"`) or after (`"AFTER"`) this dependency. If the ordering does not matter, return `"NONE"` | `"AFTER"` -`side` | string | `"BOTH"` | The [physical side][dist] the dependency must be present on: `"CLIENT"`, `"SERVER"`, or `"BOTH"`.| `"CLIENT"` -`referralUrl` | string | *nothing* | A URL to the download page of the dependency. Currently unused. | `"https://library.example.com/"` +| Property | Type | Default | Description | Example | +|:---------------|:-------:|:-------------:|:---------------------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------| +| `modId` | string | **mandatory** | The identifier of the mod added as a dependency. | `modId="jei"` | +| `mandatory` | boolean | **mandatory** | Whether the game should crash when this dependency is not met. | `mandatory=true` | +| `versionRange` | string | `""` | The acceptable version range of the language loader, expressed as a [Maven Version Range][mvr]. An empty string matches any version. | `versionRange="[1, 2)"` | +| `ordering` | string | `"NONE"` | Defines if the mod must load before (`"BEFORE"`) or after (`"AFTER"`) this dependency. If the ordering does not matter, return `"NONE"` | `ordering="AFTER"` | +| `side` | string | `"BOTH"` | The [physical side][dist] the dependency must be present on: `"CLIENT"`, `"SERVER"`, or `"BOTH"`. | `side="CLIENT"` | +| `referralUrl` | string | *nothing* | A URL to the download page of the dependency. Currently unused. | `referralUrl="https://library.example.com/"` | :::danger -The `ordering` of two mods may cause a crash due to a cyclic dependency: for example, mod A must load `"BEFORE"` mod B and mod B `"BEFORE"` mod A. +The `ordering` of two mods may cause a crash due to a cyclic dependency, for example if mod A must load `"BEFORE"` mod B and at the same time, mod B must load `"BEFORE"` mod A. ::: -Mod Entrypoints ---------------- +## Mod Entrypoints -Now that the `mods.toml` is filled out, we need to provide an entrypoint to being programming the mod. Entrypoints are essentially the starting point for executing the mod. The entrypoint itself is determined by the language loader used in the `mods.toml`. +Now that the `mods.toml` is filled out, we need to provide an entrypoint for the mod. Entrypoints are essentially the starting point for executing the mod. The entrypoint itself is determined by the language loader used in the `mods.toml`. ### `javafml` and `@Mod` -`javafml` is a language loader provided by Forge for the Java programming language. The entrypoint is defined using a public class with the `@Mod` annotation. The value of `@Mod` must contain one of the mod ids specified within the `mods.toml`. From there, all initialization logic (e.g., [registering events][events], [adding `DeferredRegister`s][registration]) can be specified within the constructor of the class. The mod bus can be obtained from `FMLJavaModLoadingContext`. +`javafml` is a language loader provided by NeoForge for the Java programming language. The entrypoint is defined using a public class with the `@Mod` annotation. The value of `@Mod` must contain one of the mod ids specified within the `mods.toml`. From there, all initialization logic (e.g. [registering events][events] or [adding `DeferredRegister`s][registration]) can be specified within the constructor of the class. ```java -@Mod("examplemod") // Must match mods.toml +@Mod("examplemod") // Must match a mod id in the mods.toml public class Example { - - public Example() { + public Example(IEventBus modBus) { // The parameter is the mod-specific event bus, needed e.g. for registration and events // Initialize logic here - var modBus = FMLJavaModLoadingContext.get().getModEventBus(); - - // ... } } ``` +:::note +There must be a 1-to-1 matching of mods in the `mods.toml` file and `@Mod` entrypoints. This means that for every mod defined, there must be exactly one `@Mod` annotation with that mod's id. +::: + ### `lowcodefml` `lowcodefml` is a language loader used as a way to distribute datapacks and resource packs as mods without the need of an in-code entrypoint. It is specified as `lowcodefml` rather than `nocodefml` for minor additions in the future that might require minimal coding. -[toml]: https://toml.io/ -[mvr]: https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html -[spdx]: https://spdx.org/licenses/ -[modsp]: #mod-specific-properties -[uses]: https://docs.oracle.com/javase/specs/jls/se17/html/jls-7.html#jls-7.7.3 -[serviceload]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html#load(java.lang.Class) [array]: https://toml.io/en/v1.0.0#array-of-tables -[mvnver]: ./versioning.md -[multiline]: https://toml.io/en/v1.0.0#string -[update]: ../misc/updatechecker.md -[features]: #features -[sides]: ../concepts/sides.md#writing-one-sided-mods +[atlasviewer]: https://github.com/XFactHD/AtlasViewer/blob/1.20.2/neoforge/src/main/resources/META-INF/services/xfacthd.atlasviewer.platform.services.IPlatformHelper [dist]: ../concepts/sides.md#different-kinds-of-sides [events]: ../concepts/events.md +[features]: #features +[group]: #the-group-id +[javafml]: #javafml-and-mod +[jei]: https://www.curseforge.com/minecraft/mc-mods/jei +[lowcodefml]: #lowcodefml +[mcversioning]: versioning.md#minecraft +[mdkgradleproperties]: https://github.com/neoforged/MDK/blob/main/gradle.properties +[mdkmodstoml]: https://github.com/neoforged/MDK/blob/main/src/main/resources/META-INF/mods.toml +[modstoml]: #modstoml +[mojmaps]: https://github.com/neoforged/NeoForm/blob/main/Mojang.md +[multiline]: https://toml.io/en/v1.0.0#string +[mvr]: https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html +[neoversioning]: versioning.md#neoforge +[packaging]: ./structuring.md#packaging [registration]: ../concepts/registries.md#deferredregister +[serviceload]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html#load(java.lang.Class) +[sides]: ../concepts/sides.md#writing-one-sided-mods +[spdx]: https://spdx.org/licenses/ +[toml]: https://toml.io/ +[update]: ../misc/updatechecker.md +[uses]: https://docs.oracle.com/javase/specs/jls/se17/html/jls-7.html#jls-7.7.3 +[versioning]: ./versioning.md diff --git a/docs/gettingstarted/structuring.md b/docs/gettingstarted/structuring.md index 64101547..cdb65a5e 100644 --- a/docs/gettingstarted/structuring.md +++ b/docs/gettingstarted/structuring.md @@ -1,14 +1,12 @@ -Structuring Your Mod -==================== +# Structuring Your Mod -Structured mods are beneficial for maintenance, making contributions, and providing a clearer understanding of the underlying codebase. Some of the recommendations from Java, Minecraft, and Forge are listed below. +Structured mods are beneficial for maintenance, making contributions, and providing a clearer understanding of the underlying codebase. Some of the recommendations from Java, Minecraft, and NeoForge are listed below. :::note You do not have to follow the advice below; you can structure your mod any way you see fit. However, it is still highly recommended to do so. ::: -Packaging ---------- +## Packaging When structuring your mod, pick a unique, top-level package structure. Many programmers will use the same name for different classes, interfaces, etc. Java allows classes to have the same name as long as they are in different packages. As such, if two classes have the same package with the same name, only one would be loaded, most likely causing the game to crash. @@ -19,7 +17,7 @@ b.jar - com.example.ExampleClass // This class will not normally be loaded ``` -This is even more relevant when it comes to loading modules. If there are class files in two packages under the same name in separate modules, this will cause the mod loader **to crash on startup** since mod modules are exported to the game and other mods. +This is even more relevant when it comes to loading modules. If there are class files in two packages under the same name in separate modules, this will cause the mod loader to crash on startup since mod modules are exported to the game and other mods. ``` module A @@ -33,13 +31,13 @@ module B - class T ``` -As such, your top level package should be something that you own: a domain, email address, a subdomain of where your website, etc. It can even be your name or username as long as you can guarantee that it will be uniquely identifiable within the expected target. +As such, your top level package should be something that you own: a domain, email address, a (subdomain of a) website, etc. It can even be your name or username as long as you can guarantee that it will be uniquely identifiable within the expected target. Furthermore, the top-level package should also match your [group id][group]. -Type | Value | Top-Level Package -:---: | :---: | :--- -Domain | example.com | `com.example` -Subdomain | example.github.io | `io.github.example` -Email | example@gmail.com | `com.gmail.example` +| Type | Value | Top-Level Package | +|:---------:|:-----------------:|:--------------------| +| Domain | example.com | `com.example` | +| Subdomain | example.github.io | `io.github.example` | +| Email | example@gmail.com | `com.gmail.example` | The next level package should then be your mod's id (e.g. `com.example.examplemod` where `examplemod` is the mod id). This will guarantee that, unless you have two mods with the same id (which should never be the case), your packages should not have any issues loading. @@ -49,17 +47,16 @@ You can find some additional naming conventions on [Oracle's tutorial page][nami In addition to the top-level package, it is highly recommend to break your mod's classes between subpackages. There are two major methods on how to do so: -* **Group By Function**: Make subpackages for classes with a common purpose. For example, blocks can be under `block` or `blocks`, entities under `entity` or `entities`, etc. Mojang uses this structure with the singular version of the word. +* **Group By Function**: Make subpackages for classes with a common purpose. For example, blocks can be under `block`, items under `item`, entities under `entity`, etc. Minecraft itself uses a similar structure (with some exceptions). * **Group By Logic**: Make subpackages for classes with a common logic. For example, if you were creating a new type of crafting table, you would put its block, menu, item, and more under `feature.crafting_table`. #### Client, Server, and Data Packages -In general, code only for a given side or runtime should be isolated from the other classes in a separate subpackage. For example, code related to [data generation][datagen] should go in a `data` package while code only on the dedicated server should go in a `server` package. +In general, code only for a given side or runtime should be isolated from the other classes in a separate subpackage. For example, code related to [data generation][datagen] should go in a `data` package, and code only on the dedicated server should go in a `server` package. -However, it is highly recommended that [client-only code][sides] should be isolated in a `client` subpackage. This is because dedicated servers have no access to any of the client-only packages in Minecraft. As such, having a dedicated package would provide a decent sanity check to verify you are not reaching across sides within your mod. +It is highly recommended that [client-only code][sides] should be isolated in a `client` subpackage. This is because dedicated servers have no access to any of the client-only packages in Minecraft and will crash if your mod tries to access them anyway. As such, having a dedicated package provides a decent sanity check to verify you are not reaching across sides within your mod. -Class Naming Schemes --------------------- +## Class Naming Schemes A common class naming scheme makes it easier to decipher the purpose of the class or to easily locate specific classes. @@ -73,11 +70,11 @@ Classes are commonly suffixed with its type, for example: Mojang typically follows a similar structure for all classes except entities. Those are represented by just their names (e.g. `Pig`, `Zombie`, etc.). ::: -Choose One Method from Many ---------------------------- +## Choose One Method from Many -There are many methods for performing a certain task: registering an object, listening for events, etc. It's generally recommended to be consistent by using a single method to accomplish a given task. While this does improve code formatting, it also avoid any weird interactions or redundancies that may occur (e.g. your event listener executing twice). +There are many methods for performing a certain task: registering an object, listening for events, etc. It's generally recommended to be consistent by using a single method to accomplish a given task. This improves readability and avoids weird interactions or redundancies that may occur (e.g. your event listener running twice). +[group]: index.md#the-group-id [naming]: https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html [datagen]: ../datagen/index.md [sides]: ../concepts/sides.md diff --git a/docs/gettingstarted/versioning.md b/docs/gettingstarted/versioning.md index 2db561eb..b6203418 100644 --- a/docs/gettingstarted/versioning.md +++ b/docs/gettingstarted/versioning.md @@ -1,57 +1,96 @@ -Versioning -========== +# Versioning -In general projects, [semantic versioning][semver] is often used (which has the format `MAJOR.MINOR.PATCH`). However, in the case of modding it may be more beneficial to use the format `MCVERSION-MAJORMOD.MAJORAPI.MINOR.PATCH` to be able to differentiate between world-breaking and API-breaking changes of a mod. +This article will break down how versioning works in Minecraft and NeoForge, and will give some recommendations for mod versioning as well. -:::caution -Forge uses [Maven version ranges][cmpver] to compare version strings, which is not fully compatible with the Semantic Versioning 2.0.0 spec, such as the 'prerelease' tag. +## Minecraft + +Minecraft uses [semantic versioning][semver]. Semantic versioning, or "semver" for short, has the format `major.minor.patch`. So for example, Minecraft 1.20.2 has the major version 1, the minor version 20 and the patch version 2. + +Minecraft has used `1` as the major version since 2011, when Minecraft 1.0 was introduced. Before that, the versioning scheme changed often, and there were versions like `a1.1` (Alpha 1.1), `b1.7.3` (Beta 1.7.3) or even the `infdev` versions, which didn't follow a clear versioning scheme at all. Due to the `1` major version holding up for over a decade now, and due to the in-joke that is Minecraft 2, it is generally considered unlikely that this is ever going to change. + +### Snapshots + +Snapshots deviate from the standard semver scheme. They are labeled as `YYwWWa`, where `YY` represents the last two digits of the year (e.g. `23`) and `WW` represents the week of that year (e.g. `01`). So for example, snapshot `23w01a` is the snapshot released in the first week of 2023. + +The `a` suffix exists for occasions where two snapshots get released in the same week (where the second snapshot would then be named something like `23w01b`). Mojang has occasionally used this in the past. The alternative suffix has also been used for snapshots like `20w14infinite`, which was the [2020 infinite dimensions April Fool's joke][infinite]. + +### Pre-releases and Release Candidates + +When a snapshot cycle is coming completion, Mojang starts releasing so-called pre-releases. Pre-releases are deemed feature-complete for a version and focus solely on bugfixes. They use the semver notation for the version it is for, suffixed by `-preX`. So for example, the first pre-release for 1.20.2 was named `1.20.2-pre1`. There can be and usually are multiple pre-releases, which are accordingly suffixed with `-pre2`, `-pre3`, etc. + +Similarly, when the pre-release cycle completes, Mojang releases Release Candidate 1 (suffixing the version with `-rc1`, for example `1.20.2-rc1`). Mojang aims to have one release candidate that they can release if no further bugs occur. However, if an unexpected bug occurs, then there can also be an `-rc2`, `-rc3`, etc. version, similar to pre-releases. + +## NeoForge + +NeoForge uses an adapted semver system: The major version is Minecraft's minor version, the minor version is Minecraft's patch version, and the patch version is the "actual" NeoForge version. So for example, NeoForge 20.2.59 is the 60th version (we start at 0) for Minecraft 1.20.2. The `1` at the beginning is omitted because it is very unlikely that it will ever change, see [above][minecraft] for why that is the case. + +A few places in NeoForge also use [Maven version ranges][mvr], for example the Minecraft and NeoForge version ranges in the [`mods.toml`][modstoml] file. These are mostly, but not fully compatible with semver (the `pre`-tag is not considered by it, for example). + +## Mods + +There is no definitive best versioning system. Different styles of development, scopes of projects, etc. all influence the decision of what versioning system to use. Sometimes, versioning system can also be combined. This section attempts to give an overview over some commonly used versioning systems, with real-life examples. + +Usually, a mod's file name looks like `modid-.jar`. So if our mod id is `examplemod` and our version is `1.2.3`, our mod file would be named `examplemod-1.2.3.jar`. + +:::note +Versioning systems are suggestions, rather than strictly enforced rules. This is especially true with regard to when the version is changed ("bumped"), and in what way. If you want to use a different versioning system, nobody is going to stop you. ::: -Examples --------- +### Semantic Versioning + +Semantic versioning ("semver") consists of three parts: `major.minor.patch`. The major version is bumped when major changes are made to the codebase, which usually correlates with major new features and bugfixes. The minor version is bumped when minor features are introduced, and patch bumps happen when an update only includes bugs. -Here is a list of examples that can increment the various variables. +It is generally agreed upon that any version `0.x.x` is a development version, and with the first (full) release, the version should be bumped to `1.0.0`. -* `MCVERSION` - * Always matches the Minecraft version the mod is for. -* `MAJORMOD` - * Removing items, blocks, block entities, etc. - * Changing or removing previously existing mechanics. - * Updating to a new Minecraft version. -* `MAJORAPI` - * Changing the order or variables of enums. - * Changing return types of methods. - * Removing public methods altogether. -* `MINOR` - * Adding items, blocks, block entities, etc. - * Adding new mechanics. - * Deprecating public methods. (This is not a `MAJORAPI` increment since it doesn't break an API.) -* `PATCH` - * Bugfixes. +The "minor for features, patch for bugfixes" rule is often disregarded in practice. A popular example for this is Minecraft itself, which does major features through the minor version number, minor features through the patch number, and bugfixes in snapshots (see above). -When incrementing any variable, all lesser variables should reset to `0`. For instance, if `MINOR` would increment, `PATCH` would become `0`. If `MAJORMOD` would increment, all other variables would become `0`. +Depending on how often a mod is updated, these numbers can be smaller or larger. For example, [Supplementaries][supplementaries] is on version `2.6.31` (at the time of writing). Triple- or even quadruple-digit numbers, especially in the `patch`, are absolutely possible. -### Work In Progress +### "Reduced" and "Expanded" Semver -If you are in the initial development stage of your mod (before any official releases), the `MAJORMOD` and `MAJORAPI` should always be `0`. Only `MINOR` and `PATCH` should be updated every time you build your mod. Once you build an official release (most of the time with a stable API), you should increment `MAJORMOD` to version `1.0.0.0`. For any further development stages, refer to the [Prereleases][pre] and [Release candidates][rc] section of this document. +Sometimes, semver can be seen with only two numbers. This is a sort of "reduced" semver, or "2-part" semver. Their version numbers only have a `major.minor` scheme. This is commonly used by small mods that only add a few simple objects and thus rarely need updates (except Minecraft version updates), often staying at version `1.0` forever. -### Multiple Minecraft Versions +"Expanded" semver, or "4-part" semver, has four numbers (so something like `1.0.0.0`). Depending on the mod, the format can be `major.api.minor.patch`, or `major.minor.patch.hotfix`, or something different entirely - there is no standard way to do it. -If the mod upgrades to a new version of Minecraft, and the old version will only receive bug fixes, the `PATCH` variable should be updated based on the version before the upgrade. If the mod is still in active development in both the old and the new version of Minecraft, it is advised to append the version to **both** build numbers. For example, if the mod is upgraded to version `3.0.0.0` due to a Minecraft version change, the old mod should also be updated to `3.0.0.0`. The old version will become, for example, version `1.7.10-3.0.0.0`, while the new version will become `1.8-3.0.0.0`. If there are no changes at all when building for a newer Minecraft version, all variables except for the Minecraft version should stay the same. +For `major.api.minor.patch`, the `major` version is decoupled from the `api` version. This means that the `major` (feature) bit and the `api` bit can be bumped independently. This is commonly used by mods that expose an API for other modders to use. For example, [Mekanism][mekanism] is currently on version 10.4.5.19 (at the time of writing). -### Final Release +For `major.minor.patch.hotfix`, the patch level is split into two. This is the approach used by the [Create][create] mod, which is currently on version 0.5.1f (at the time of writing). Note that Create denotes the hotfix as a letter instead of a fourth number, in order to stay compatible with regular semver. -When dropping support for a Minecraft version, the last build for that version should get the `-final` suffix. This denotes that the mod will no longer be supported for the denoted `MCVERSION` and that players should upgrade to a newer version of the mod to continue receiving updates and bug fixes. +:::info +Reduced semver, expanded semver, 2-part semver and 4-part semver are not official terms or standardized formats in any way. +::: -### Pre-releases +### Alpha, Beta, Release -It is also possible to prerelease work-in-progress features, which means new features are released that are not quite done yet. These can be seen as a sort of "beta". These versions should be appended with `-betaX`, where `X` is the number of the prerelease. (This guide does not use `-pre` since, at the time of writing, it is not a valid alias for `-beta`.) Note that already released versions and versions before the initial release can not go into prerelease; variables (mostly `MINOR`, but `MAJORAPI` and `MAJORMOD` can also prerelease) should be updated accordingly before adding the `-beta` suffix. Versions before the initial release are simply work-in-progress builds. +Like Minecraft itself, modding is often done in the classical `alpha`/`beta`/`release` stages known from software engineering, where `alpha` denotes an unstable/experimental version (sometimes also called `experimental` or `snapshot`), `beta` denotes a semi-stable version, and `release` denotes a stable version (sometimes called `stable` instead of `release`). -### Release Candidates +Some mods use their major version to denote a Minecraft version bump. An example of this is [JEI][jei], which uses `13.x.x.x` for Minecraft 1.19.2, `14.x.x.x` for 1.19.4, and `15.x.x.x` for 1.20.1 (there are no versions for 1.19.3 and 1.20.0). Others append the tag to the mod name, for example the [Minecolonies][minecolonies] mod, which is on `1.1.328-BETA` at the time of writing. -Release candidates act as prereleases before an actual version change. These versions should be appended with `-rcX`, where `X` is the number of the release candidate which should, in theory, only be increased for bugfixes. Already released versions can not receive release candidates; variables (mostly `MINOR`, but `MAJORAPI` and `MAJORMOD` can also prerelease) should be updated accordingly before adding the `-rc` suffix. When releasing a release candidate as stable build, it can either be exactly the same as the last release candidate or have a few more bug fixes. +### Including the Minecraft Version -[semver]: https://semver.org/ -[cmpver]: https://maven.apache.org/ref/3.5.2/maven-artifact/apidocs/org/apache/maven/artifact/versioning/ComparableVersion.html +It is common to include the Minecraft version a mod is for in the filename. This makes it easier for end users to easily find out what Minecraft version a mod is for. A common place for this is either before or after the mod version, with the former being more widespread than the latter. For example, JEI version `16.0.0.28` (latest at the time of writing) for 1.20.2 would become `jei-1.20.2-16.0.0.28` or `jei-16.0.0.28-1.20.2`. + +### Including the Mod Loader + +As you probably know, NeoForge is not the only mod loader out there, and many mod developers develop on multiple platforms. As a result, a way to distinguish between two files of the same mod of the same version, but for different mod loaders is needed. + +Usually, this is done by including the mod loader somewhere in the name. `jei-neoforge-1.20.2-16.0.0.28`, `jei-1.20.2-neoforge-16.0.0.28` or `jei-1.20.2-16.0.0.28-neoforge` are all valid ways to do it. For other mod loaders, the `neoforge` bit would be replaced with `forge`, `fabric`, `quilt` or whatever different mod loader you might be developing on alongside NeoForge. + +### A Note on Maven + +Maven, the system used for dependency hosting, uses a versioning system that differs from semver in some details (though the general `major.minor.patch` pattern remains the same). The related [Maven Versioning Range (MVR)][mvr] system is used in some places in NeoForge (see [above][neoforge]). When choosing your versioning scheme, you should make sure it is compatible with MVR, as otherwise, mods will not be able to depend on specific versions of your mod! + +[create]: https://www.curseforge.com/minecraft/mc-mods/create +[infinite]: https://minecraft.wiki/w/Java_Edition_20w14∞ +[jei]: https://www.curseforge.com/minecraft/mc-mods/jei +[mekanism]: https://www.curseforge.com/minecraft/mc-mods/mekanism +[minecolonies]: https://www.curseforge.com/minecraft/mc-mods/minecolonies +[minecraft]: #minecraft +[modstoml]: modfiles.md#modstoml +[mvr]: https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html +[mvr]: https://maven.apache.org/ref/3.5.2/maven-artifact/apidocs/org/apache/maven/artifact/versioning/ComparableVersion.html +[neoforge]: #neoforge [pre]: #pre-releases [rc]: #release-candidates +[semver]: https://semver.org/ +[supplementaries]: https://www.curseforge.com/minecraft/mc-mods/supplementaries