Skip to content
InputBooster
Developer DocumentationScreens

Building and testing

Build all three supported jars from source, run the test suite, and understand what the CI pipeline does.

4 min readInputBooster 4.1.2-alphaMinecraft 26.2 / 26.3

Java 25 and a network connection for the Gradle toolchain are required. The repository builds a NeoForge jar and two Fabric jars from one core source tree.

Requirements

RequirementValue
Java25, set through the Gradle toolchain
NetworkRequired for the first build to fetch the toolchain and dependencies
GradleProvided by the wrapper — do not install it separately

The build sets a Java toolchain explicitly:

groovy
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

The two Gradle builds

The repository has two Gradle projects.

ProjectDirectoryLoaderMinecraft
Root.NeoForge26.2
Fabricfabric/Fabric26.3 by default

Both compile the same core sources. The root project adds src/neoforge/java and one compat source set; the Fabric project adds fabric/src/main/java and its own compat source set.

groovy
sourceSets {
    main {
        java {
            srcDirs = ['src/main/java', 'src/neoforge/java', 'src/compat/mc26_2/java']
        }
    }
}

Building

NeoForge, Minecraft 26.2

Root project
$ ./gradlew build

Fabric, Minecraft 26.3

Fabric project
$ cd fabric && ./gradlew build

Fabric, Minecraft 26.2

Fabric 26.2 override
$ ./gradlew build -Pminecraft_version=26.2 "-Pminecraft_version_range=>=26.2 <26.3" -Pfabric_version=0.161.0+26.2

On Windows, use gradlew.bat instead of ./gradlew.

Where the jars land

BuildOutput
NeoForgebuild/libs/inputbooster-<version>-nf-mc262.jar
Fabricfabric/build/libs/inputbooster-<version>-fabric-mc263.jar

The version string comes from gradle.properties and carries the loader flavour, for example 4.1.2-alpha-fabric or 4.1.2-alpha-nf-mc262.

Running the tests

The test suite
$ cd fabric && ./gradlew test

There are 16 test classes in fabric/src/test/java/dev/inputbooster:

TestWhat it covers
AdaptivePollRateTestThe auto poll rate targets, ramp and instability clamp
ComboKeyPresetsTestThe Ctrl+1-5 preset values and the latch
CpsLimiterTestThe token bucket
CpsLimiterBurstTestBurst behaviour against the bucket
CpsLimiterModesTestFIXED, HUMANIZED, WEAPON_AWARE and COOLDOWN
EngineConfigTestEngine mode resolution
FabricDependencyRangeTestThe Fabric dependency range form
InputActionQueueTestThe queue bound and the counter
InputBoosterConfigTestConfig round trips and validation
InputEngineTestEdge detection across both sources
LatencyProfilerTestThe rolling window and the peak
MixinDeclarationTestThe mixin declaration rules
MixinTargetSignatureTestEvery hook signature against the real Minecraft jar
ProfileAndReplayTestProfile capture, apply and replay behaviour
SessionStatsTestThe CPS buckets and the session counters
SuppressionAndOriginTestThe tick-scoped suppression tokens and the replay origin

The changelog for 4.1.0-alpha records 81 tests in total.

The two tests that guard the mod

MixinDeclarationTest and MixinTargetSignatureTest exist because of two release-stopping crashes.

MixinDeclarationTest fails the build if a registered mixin declares a non-private static method. Mixin only permits private static helpers inside a mixin, and a public one aborts the transformation of the whole target class. That bug shipped in 4.0.2-stable and crashed every client before the main menu.

MixinTargetSignatureTest checks every @Inject, @Accessor and @Invoker against the resolved Minecraft jar, for both the 26.2 and 26.3 builds. It exists because 4.1.0-alpha crashed on every loader: the keyboard mixin was written against the 1.21 signature keyPress(long, int, int, int, int) while 26.2 and 26.3 use keyPress(long, int, KeyEvent).

CI

The gradle.yml workflow runs on pushes to main and fabric-26.2-26.3, on v* tags, on pull requests targeting main, and through manual workflow dispatch.

JobWhat it does
build-neoforgeBuilds the NeoForge 26.2 jar on Temurin 25
build-fabricBuilds both Fabric jars from a matrix, then verifies the metadata
releasePublishes a GitHub release with all three jars

The Fabric job verifies the dependency range form before it uploads anything:

bash
grep -q '"minecraft": *">=' /tmp/fabric.mod.json \
  || { echo "minecraft dependency must use the '>=x <y' form" >&2; exit 1; }

The release job refuses to publish unless all three jars are present, derives the tag from mod_version when there is no explicit tag, and marks a release as a prerelease when the version contains alpha or beta.

Fabric unit tests and build matrix

The test.yml workflow adds a dedicated Fabric test-and-build job. It runs on pushes to main and fabric-26.2-26.3 when files under fabric/ or src/, or the workflow itself, change. It can also be started manually from GitHub Actions.

Matrix targetMinecraft rangeFabric API
Fabric 26.2>=26.2 <26.30.161.0+26.2
Fabric 26.3>=26.3 <26.40.161.0+26.3

Each matrix job uses Temurin Java 25 and runs ./gradlew clean test build --no-daemon from fabric/, passing the matching Minecraft version, dependency range and Fabric API version. JUnit reports are uploaded even when a test fails; the Fabric jar is uploaded only after a successful build. Both artifact types are retained for 14 days.

Headless client smoke test

The client-smoke.yml workflow uses the same two-version Fabric matrix and push/path filters, and also supports manual dispatch. It starts runClient under Xvfb with Mesa software rendering and a null audio backend, so CI does not need a physical display or audio device.

The check waits up to 210 seconds for the client log marker Sound engine started, then verifies that the client remains running for another 10 seconds. It uploads the client console, game logs and crash reports for 14 days.

Running the mod in a development client

Both Gradle projects define a client run configuration:

bash
./gradlew runClient

The NeoForge root project sets neoforge.enabledGameTestNamespaces to the mod id, so game tests in that namespace run in the development client.