Skip to main content
Version: Minecraft 26.2

Create the project

Run initPolyMod in the template folder you unzipped (crystal-garden). It renames the mod ID, name, package, entrypoint class, and project name in place.

.\gradlew.bat initPolyMod -PmodId=crystal_garden "-PmodName=Crystal Garden" "-PmodPackage=com.example.crystalgarden"
.\gradlew.bat build

If build succeeds, you are ready. You can skip Rename the template by hand below. initPolyMod works only on an unchanged copy of the template; to start over, unzip the template again. The properties and their defaults are in Mod development tools.

The generated project​

crystal-garden/
├─ settings.gradle.kts project name, where Gradle finds Poly Mod Loader
├─ build.gradle.kts mod plugin dev.polymodloader.mod
├─ gradle.properties Minecraft version to run (optional)
├─ .run/runClient.run.xml IntelliJ run configuration
├─ src/main/java/com/example/crystalgarden/CrystalGardenMod.java entrypoint
└─ src/main/resources/poly.mod.json mod metadata

The template includes a ruby item and a ruby block as examples. The next pages replace them with the Crystal Garden code.

settings.gradle.kts
pluginManagement {
// -PpolyLocalSdk: use a local Poly Mod Loader build (./gradlew publishToMavenLocal and
// ./gradlew -p build-logic publishToMavenLocal in Poly Mod Loader) even for a version that is published.
val localFirst = providers.gradleProperty("polyLocalSdk").isPresent
repositories {
if (localFirst) mavenLocal()
// The Poly Mod Loader SDK: the dev.polymodloader.mod plugin and, through it, Poly Mod Loader itself.
maven("https://www.polymc.net/maven/") {
name = "Poly Mod Loader"
content { includeGroupByRegex("dev\\.polymodloader(\\..*)?") }
}
// A local Poly Mod Loader build of a version the SDK repository does not have.
if (!localFirst) mavenLocal()
gradlePluginPortal()
}
}

rootProject.name = "crystal-garden"

Gradle looks for the dev.polymodloader.mod plugin, and through it Poly Mod Loader itself, on the Poly Mod Loader website's Maven repository first (only the dev.polymodloader group), then in Maven Local, then on the Gradle Plugin Portal. It takes a version from the first repository that has it. -PpolyLocalSdk puts Maven Local first, for contributors who test a local Poly Mod Loader build (Get the mod template).

The first line of build.gradle.kts is the Poly Mod Loader mod plugin.

build.gradle.kts (first part)
plugins {
id("dev.polymodloader.mod") version "0.2.0-beta.2"
}

group = "com.example"
version = "0.1.0"

The dev.polymodloader.mod plugin provides the following.

  • A Java 25 toolchain
  • compileOnly dependencies: the Native API (poly-lifecycle-api) and SLF4J. Poly Mod Loader provides them at run time, so they do not go into the mod jar
  • validatePolyModJson: checks poly.mod.json with the same validator Poly Mod Loader uses (part of check)
  • polyResources and generatePolyResources: generate the model, block state, loot, and name files for blocks and items at build time
  • checkPolyResources: finds mistakes in file names, JSON, and model and texture references before you start the game (part of check)
  • Run and verification tasks: runClient, runServer, gameTests, worldCreateSaveTest, clientWorldReloadTest, serverBootSmokeTest

Rename the template by hand​

You can also rename the unzipped template yourself instead of running initPolyMod. Change the following four places.

What to changeExample
id, name, and entrypoints in poly.mod.json"id": "crystal_garden"
Java package and classescom.example.mymod.MyMod → com.example.crystalgarden.CrystalGardenMod
Resource foldersassets/my_mod/ → assets/crystal_garden/, data/crystal_garden/
settings.gradle.kts, build.gradle.ktsrootProject.name, group, the log line that worldCreateSaveTest checks

Use only lowercase letters, digits, and underscores in a mod ID.

Mod ID and resource folders

If a resource folder name differs from the mod ID, the game cannot find models, textures, or translations. If you see a purple and black checkered texture in game, check the folder names first.

Next step​

Fill in poly.mod.json.

Buy me a coffee