An advanced Java mod template for Mindustry, designed for experienced modders. It features a robust annotation-driven code generation system, an automated asset processing pipeline, GitHub Actions CI for cross-platform builds, and Jabel integration for modern Java syntax with Java 8 bytecode compatibility.
This template is based on the public version of the ProjectUnity mod by the AvantTeam.
Before diving in, a good understanding of Java and Git is highly recommended. While not impossible to start without, you'll likely encounter fewer hurdles with prior experience. The Mindustry modding community, particularly on Discord, is a great resource for help.
- Install Prerequisites:
- JDK 17 or higher: This is essential for compiling the template and your mod. Checked by
settings.gradle. - IDE (Recommended): IntelliJ IDEA (Community Edition is free) is strongly suggested over basic text editors.
- JDK 17 or higher: This is essential for compiling the template and your mod. Checked by
- Create Your Repository:
- Click the
Use this templatebutton on the GitHub repository page (or your fork). - Select "Create a new repository."
- Click the
- Clone Your Repository:
- Clone the newly created repository to your local machine.
Important
A local copy is not the ZIP archive you can download from GitHub. Use git clone https://github.com/YOUR_USERNAME/YOUR_REPOSITORY_NAME.git or the cloning feature provided by your Git client (like GitHub Desktop), for version control and keeping your sanity.
Downloading the ZIP bypasses Git's version control capabilities.
-
Configure Your Mod:
This template is designed to make initial setup straightforward. You'll primarily need to modify the following:
mod.json: This file contains your mod's metadata.name: The internal, unique ID for your mod (e.g.,my-awesome-mod). This is critical.- Java Package Naming: For Java compatibility, this
namewill be "sanitized" by removing hyphens (e.g.,my-awesome-modbecomesmyawesomemod) when forming Java package names for both your manually created code and generated code. - It's highly recommended that your main Java package and related initial
templatefolders (likemain/src/template,annotations/src/template/annotations,tools/src/template/tools) are renamed to match this sanitized value (e.g., ifnameismy-awesome-mod, rename thetemplatepackage tomyawesomemod). This consistency greatly improves clarity and compatibility.
- Java Package Naming: For Java compatibility, this
displayName: The user-friendly name shown in Mindustry's mod browser (e.g.,My Awesome Mod). This also influences the default names of your built JAR files via Gradle and the artifacts generated by GitHub Actions.author: Your name or your team's name.description: A brief description of your mod.version: Your mod's version (e.g.,1.0.0).minGameVersion: The minimum Mindustry version your mod supports (e.g.,149).main: The fully qualified name of your main mod class (e.g.,myawesomemod.MyAwesomeMod).
gradle.properties:classPrefix: A prefix for certain generated Java classes (likeYourPrefixSounds.java,YourPrefixEntityMapping.java). If left empty, it defaults to yourdisplayNamefrommod.json(with spaces removed). For example, ifdisplayNameis "My Awesome Mod",classPrefixwould default toMyAwesomeMod.mindustryPath(Optional): Path to your Mindustry installation directory.- If this path points to a Steam Mindustry installation (containing
Mindustry.exe), tasks likeinstall,installClient, andrunClientwill correctly target its subdirectories (e.g.,saves/mods/). - If set to a non-Steam directory, these tasks will use a
modssubdirectory within it (e.g.[mindustryPath]/mods/). - If left empty, tasks default to using a
run/directory within your project's root (e.g.,[projectDir]/run/mods/forinstall,[projectDir]/run/client-[version].jarforinstallClient). Thisrun/directory will be created if it doesn't exist.
- If this path points to a Steam Mindustry installation (containing
mindustryVersion: The version of Mindustry client to download for theinstallClientandrunClienttasks (e.g.,v146). This should match a release tag on Mindustry's GitHub repository.
- Java Source Files:
- Rename the default package
templateinmain/src/to your sanitized mod name (e.g., tomyawesomemodif yourmod.jsonnameismy-awesome-mod). - Rename the main mod class
main/src/(your-new-package-name)/Template.javato your desired class name (e.g.,MyAwesomeMod.java). - Ensure the
mainproperty inmod.jsonmatches the new fully qualified name of this class (e.g.,myawesomemod.MyAwesomeMod). - Refactor package names within the
annotationsandtoolsmodules similarly (e.g.,annotations/src/template/annotations/...toannotations/src/myawesomemod/annotations/...). - Update the
packagedeclarations within the Java files in these refactored directories.
- Rename the default package
Here's an example of a properly configured mod base, assuming the mod's
displayNameis "My Awesome Mod" andnameinmod.jsonismy-awesome-mod(leading to sanitized package namemyawesomemod):Loading--- title: Project Hierarchy Example name my-awesome-mod sanitized package myawesomemod --- graph LR; %%{init:{'flowchart':{'nodeSpacing': 10, 'rankSpacing': 10}}}%%; classDef folder fill:#465768,stroke:#bdcedf; classDef file fill:#468868,stroke:#bdffdf; classDef importantFile fill:#884668,stroke:#ffbddf,font-weight:bold; root{{"/"}}; github{{".github/"}}; workflows{{"workflows/"}}; annotations_mod{{"annotations/"}}; annotations_src{{"src/"}}; annotations_pkg_root{{"myawesomemod/"}}; annotations_pkg_sub{{"annotations/"}}; main_mod{{"main/"}}; main_assets{{"assets/"}}; main_assets_raw{{"assets-raw/"}}; main_src{{"src/"}}; main_pkg{{"myawesomemod/"}}; tools_mod{{"tools/"}}; tools_src{{"src/"}}; tools_pkg_root{{"myawesomemod/"}}; tools_pkg_sub{{"tools/"}}; ci_yml(["ci.yml"]); mod_json(["mod.json"]); gradle_properties(["gradle.properties"]); root_build_gradle(["build.gradle"]); settings_gradle(["settings.gradle"]); main_build_gradle(["build.gradle"]); main_java_file(["MyAwesomeMod.java"]); annotations_java_file(["Annotations.java, ..."]); tools_java_file(["Tools.java, ..."]); class root,github,workflows,annotations_mod,annotations_src,annotations_pkg_root,annotations_pkg_sub,main_mod,main_assets,main_assets_raw,main_src,main_pkg,tools_mod,tools_src,tools_pkg_root,tools_pkg_sub folder; class root_build_gradle,settings_gradle,main_build_gradle file; class mod_json,gradle_properties,main_java_file,annotations_java_file,tools_java_file,ci_yml importantFile; root-->github-->workflows-->ci_yml; root-->annotations_mod-->annotations_src-->annotations_pkg_root-->annotations_pkg_sub-->annotations_java_file; root-->main_mod; main_mod-->main_assets; main_mod-->main_assets_raw; main_mod-->main_src-->main_pkg-->main_java_file; main_mod-->main_build_gradle; root-->tools_mod-->tools_src-->tools_pkg_root-->tools_pkg_sub-->tools_java_file; root-->mod_json & gradle_properties & root_build_gradle & settings_gradle;Example changes:
mod.json:{ - "name": "template", - "displayName": "Template", - "author": "Someone", - "description": "No description provided", + "name": "my-awesome-mod", + "displayName": "My Awesome Mod", + "author": "A Modder", + "description": "An awesome mod for Mindustry!", "version": "1.0", "minGameVersion": 149, - "main": "template.Template", + "main": "myawesomemod.MyAwesomeMod", "java": true, "hideBrowser": true }gradle.properties(onlyclassPrefixshown, others might be adjusted):# ... - classPrefix = + classPrefix = MyAwesomeMod # ...
main/src/myawesomemod/MyAwesomeMod.java(after renaming packagetemplatetomyawesomemodand fileTemplate.javatoMyAwesomeMod.java):- package template; + package myawesomemod; import arc.*; import arc.util.*; // ... other imports ... - import template.gen.*; + import myawesomemod.gen.*; - public class Template extends Mod{ + public class MyAwesomeMod extends Mod{ // ... }
-
Asset Workflow:
- Place your raw, unprocessed assets (e.g., original PNGs for sprites, WAV files for sounds) into the
main/assets-raw/directory. Use a logical subdirectory structure (e.g.,sprites/units/,sounds/effects/). - Run the asset processing task:
./gradlew tools:proc(orgradlew.bat tools:procon Windows). - Processed assets will be output to
main/assets/, mirroring the structure fromassets-raw/. These are the assets bundled into your mod. - Generated asset classes like
Regions.java,MyAwesomeModSounds.java(ifclassPrefixisMyAwesomeMod) will be created/updated in themain/build/generated/sources/annotationProcessor/java/main/myawesomemod/gen/directory (e.g., if your sanitized mod name ismyawesomemod) and automatically included in compilation.
That's the core setup! You can now start developing your mod.
- Place your raw, unprocessed assets (e.g., original PNGs for sprites, WAV files for sounds) into the
Mindustry Java mods are typically cross-platform. Builds are managed via Gradle.
This template uses Jabel to allow you to write modern Java syntax (e.g., Java 17 features) in your main module, which is then compiled down to Java 8 compatible bytecode. This ensures your mod can run on Mindustry instances using Java 8. All modules in this template are standardized to use Java 17.
Ideal for quick testing on PC. The resulting JAR will have Desktop appended (e.g., MyAwesomeModDesktop.jar).
-
Open your terminal in the project's root directory.
-
Ensure you have an internet connection for the first build or after a
./gradlew clean, as Gradle might download dependencies. -
Run:
./gradlew main:deploy
(Use
gradlew.bat main:deployon Windows). The JAR will be inmain/build/libs/. -
To automatically copy this JAR to your Mindustry mods folder:
./gradlew install
You can combine these:
./gradlew main:deploy install.For a complete build, install, and launch cycle for testing (will download Mindustry client if needed and not a Steam install):
./gradlew runClient
This produces a JAR compatible with both Android and PC (e.g., MyAwesomeMod.jar).
-
Using GitHub Actions (Recommended):
- Push your changes to your GitHub repository.
- The CI workflow (defined in
.github/workflows/ci.yml) will automatically build both Desktop and Android JARs using names derived from yourmod.json. - You can download these from the "Artifacts" section of the completed workflow run. The cross-platform JAR artifact might be named something like
MyAwesomeMod (in a box).zip(containingMyAwesomeMod.jar). - When you create a GitHub Release, the cross-platform JAR (e.g.,
MyAwesomeMod.jar) is automatically uploaded.
-
Local Android Build (Optional): If you need to build for Android locally:
- Install Android SDK:
- Download the "Command line tools only" package from the Android Studio page for your OS.
- Extract the ZIP to a directory (e.g.,
~/AndroidSDKon Linux/macOS,C:\AndroidSDKon Windows). - Inside the extracted
cmdline-toolsfolder, create a new folder namedlatest. Move all contents ofcmdline-tools(likebin,lib, etc.) into thislatestfolder. The structure should beAndroidSDK/cmdline-tools/latest/. - Set the
ANDROID_HOME(orANDROID_SDK_ROOT) environment variable to the full path of yourAndroidSDKdirectory (e.g.,~/AndroidSDK). Restart your terminal for changes to take effect. - Navigate your terminal to
AndroidSDK/cmdline-tools/latest/bin/. - Run
sdkmanager --licenses(orsdkmanager.bat --licenseson Windows) and accept all licenses by typing 'y' and pressing Enter for each. - Install the necessary SDK platforms and build tools. The versions are specified in
.github/workflows/ci.yml(look for thesdkmanagercommand):(Usesdkmanager "platforms;android-33" "build-tools;33.0.2"
sdkmanager.baton Windows).
- Build the Mod:
- In your mod's root directory, run:
(Use
./gradlew main:dex
gradlew.bat main:dexon Windows). - The cross-platform JAR will be located in
main/build/libs/.
- In your mod's root directory, run:
- Install Android SDK:
main:deploy: Builds the desktop-only JAR (e.g.,YourModDisplayNameDesktop.jar).main:dex: Builds the Android-compatible (cross-platform) JAR (e.g.,YourModDisplayName.jar).install: Copies themain:deployoutput (desktop JAR) to the local Mindustry mods folder. The target directory depends on themindustryPathproperty ingradle.properties:[mindustryPath]/saves/mods/ifmindustryPathpoints to a Steam installation (containsMindustry.exe).[mindustryPath]/mods/ifmindustryPathpoints to a non-Steam directory.[projectDir]/run/mods/ifmindustryPathis not set (where[projectDir]is your mod's root directory).
installClient: Downloads the Mindustry client JAR (version specified bymindustryVersionproperty ingradle.properties) into the directory determined bymindustryPath(or[projectDir]/run/ifmindustryPathis unset).- This task is skipped if the target path appears to be a Steam Mindustry installation (contains
Mindustry.exe). - Primarily used by the
runClienttask to ensure a Mindustry client is available for testing.
- This task is skipped if the target path appears to be a Steam Mindustry installation (contains
runClient: A comprehensive task to test your mod locally. It performs the following sequence:- Ensures the Mindustry client is available by running
installClient(unless it's a Steam setup). - Builds and installs your mod by running
install. - Launches Mindustry with your mod:
- If the target path (from
mindustryPathor defaulting to[projectDir]/run/) is a Steam installation, it runsMindustry.exe. - Otherwise, it runs the client JAR (e.g.,
client-[mindustryVersion].jar) usingjava -jar ... -debug.- Note: When launching the non-Steam client JAR this way, Mindustry's console output will be displayed directly in your IDE/terminal. This is not possible with the Steam version due to how Steam launches applications.
- If the target path (from
- Sets
MINDUSTRY_DATA_DIRto the appropriate data/saves directory andDEVELOPMENT=trueenvironment variables for the game instance.
- Ensures the Mindustry client is available by running
tools:proc: Runs the asset processing pipeline (defined in thetoolsmodule), processing files frommain/assets-raw/tomain/assets/.main:fetchComps: Downloads and adapts Mindustry's core entity components into a temporary build directory for compilation. This task is automatically run before compilation.updateBundles: Synchronizes localization files inmain/assets/bundles/based onbundle.properties. Changes are automatically committed and pushed by the CI workflow if changes are detected.clean: Deletes allbuilddirectories across all modules.
-
Mindustry / Arc / Other Mindustry Mods: Always use
compileOnlyin yourmain/build.gradleas these are provided by the game at runtime and should not be bundled.// In main/build.gradle dependencies { compileOnly "com.github.Anuken.Mindustry:core:$mindustryVersion" compileOnly "com.github.Anuken.Arc:arc-core:$arcVersion" // Example for another mod's API: // compileOnly "com.github.theiruser:their-mod-api:1.2.3" // For annotation processing annotationProcessor project(':annotations') compileOnly project(':annotations') // If you need to reference annotations directly in main code }
-
External Java Libraries (to be bundled with your mod): Use
implementationin yourmain/build.gradle.// In main/build.gradle dependencies { implementation "com.google.code.gson:gson:2.10.1" // Example for a JSON library }
List of planned features and improvements for the template itself.
π - Planned, π - Working on It, β
- Done
| Status | |
|---|---|
| β | Fix inconsistencies, bugs, improve quality, and enhance documentation. |
| π | Add more generating classes like PrefixSounds/PrefixMusics for other things. |
| π | Add text icon generation for mod content with support for custom icons (e.g., non-content). Investigate vanilla copy integration (e.g., Shift+Click inside Database). |
| β | Add run task kinda like Mindustry's one (runClient). |
This mod template is provided as a starting point and does not impose a specific license on your derivative work. You are free to choose the license for your mod.
Many Mindustry mods adopt the GNU GPL v3 License. If you opt for this, ensure you include a LICENSE file with the GPLv3 text in your project's root directory. Always be mindful of the licenses of Mindustry itself, Arc, and any other libraries or assets you incorporate.