-
-
Notifications
You must be signed in to change notification settings - Fork 0
Contributing
What a change to Falco is built, tested and released with: the toolchain and library versions the
build declares, the Gradle commands that compile, test and benchmark it, the conventions the build
enforces, and what a push to main publishes. It covers neither the design of the loader and the
engine — that is Anvil Chunk Loader and Light Engine — nor any
measured result, which is Measured Results. It is written for someone changing
the code rather than for someone consuming the published artefacts.
What a first build needs beyond the commands below is documented on pages of its own rather than
repeated here. A Java 25 toolchain and OneLiteFeather Maven credentials are what ./gradlew build
fails without, and both are in Installation. What the build is
made of, module by module, is Build Setup. What a test run reports, what -Werror on
doclint actually enforces and how to repeat a run are in
Testing and Javadoc; the rules the falco-archunit
module checks on every build are in Architecture Rules.
Everything in this table is declared in settings.gradle.kts, build.gradle.kts or
gradle/wrapper/gradle-wrapper.properties and is checkable there. The Pinned here column matters
for anyone reproducing a measurement: a version that is resolved rather than pinned can change under
a republication of the BOM without a single commit in this repository.
| Pinned here | ||
|---|---|---|
| Java | 25 (toolchain and release), no --enable-preview anywhere |
yes, in the root build.gradle.kts
|
| Minestom |
2026.06.20-26.1.2, compileOnly
|
no — library("minestom", …).withoutVersion(), resolved through net.onelitefeather:mycelium-bom 1.7.2
|
| Adventure |
5.1.1, adventure-nbt used directly — Minestom speaks CompoundBinaryTag natively, so there is no conversion layer |
yes, adventure-bom 5.1.1
|
| Annotations | org.jetbrains:annotations:26.1.0 |
yes |
| Tests | JUnit 6.1.0, Cyano 0.6.2 (MicrotusExtension) for anything needing a server |
no — both withoutVersion(), resolved through mycelium-bom 1.7.2
|
| Benchmarks | JMH 1.37 via me.champeau.jmh 0.7.3, in the separate falco-benchmarks module |
yes, both |
fastutil |
8.5.18 |
yes |
| Architecture | ArchUnit 1.4.2, in the separate falco-archunit module |
yes |
| Build | Gradle 9.6.1, seven modules on one shared version | yes |
The seven modules are falco-anvil, falco-light, falco-instance, falco-benchmarks,
falco-demo, falco-archunit and falco-bom; the first three are published, falco-bom publishes
only their constraints, and the other three are not published at all.
The Minestom version is the one that would invalidate a comparison silently. Every head-to-head
table under Measured measures the Minestom of the day the run happened,
and that version is decided by mycelium-bom 1.7.2, not by anything in this repository.
2026.06.20-26.1.2 is what it resolved to; a third party reproducing a number has to check that
theirs resolves to the same thing before comparing.
adventure-nbt, jetbrains-annotations and fastutil are declared explicitly rather than taken
transitively. The first two only reach the classpath through compileOnly(minestom), so any direct
use of them would compile by coincidence. fastutil is runtime scope in Minestom's POM and is
needed by the light equivalence test and the comparison benchmarks.
./gradlew build # compile, javadoc, tests — javadoc failures break the build
./gradlew :falco-anvil:test --tests "*Region*" # a subset
./gradlew :falco-benchmarks:jmhJar # build the benchmarks (they never run during build)
java -jar falco-benchmarks/build/libs/falco-benchmarks-*-jmh.jar ScalingBenchmark -f 1 -wi 2 -i 3
# Compare the two loaders on a world of your own: drop it into falco-demo/world first.
# Run both with the SAME -Pthreads, or the two numbers answer different questions.
./gradlew :falco-demo:runFalcoLoader -Pthreads=4 -Pchunks=256
./gradlew :falco-demo:runMinestomLoader -Pthreads=4 -Pchunks=256Two things that will otherwise cost an hour:
-
Do not run two Gradle builds in the same checkout at once. They corrupt
build/test-resultsand surface asEOFException,NoClassDefFoundErroror missingjacoco/test.exec— failures that look like real test breakage.rm -rf buildand rerun. -
JMH allows one instance at a time. A crashed run leaves
/tmp/jmh.lockbehind and every later run fails with "Another JMH instance might be running". Delete the file.
Match these; the build enforces some of them.
-
Javadoc on every class and method, with
@param/@return/@throws.withJavadocJar()means an incomplete comment fails CI. Class comments explain why, not what, and carry@author/@version/@since. -
Never write
@NotNull. Packages carry@NotNullByDefaultinpackage-info.java; only@Nullable,@Contractand@UnmodifiableViewappear explicitly. - Test-first, strictly. Every type here was built by writing a failing test, confirming it fails for the right reason, then implementing. Several bugs in this branch were found precisely because a test was written before the code.
- Tests are package-private, named
test<What><Expectation>, use plain JUnit assertions, and avoid@Nested. Anything needing a server uses@ExtendWith(MicrotusExtension.class). - Commits follow conventional commits, scoped
(anvil),(light),(map).
All published modules share one version. It lives on a single line of the root build.gradle.kts,
Release Please rewrites that line from the conventional commits above, and everything else follows
from it.
Push to main
|
Version | Endpoint |
|---|---|---|
| Merges the Release Please PR | the released one, 0.3.0 at ca79507
|
https://repo.onelitefeather.dev/releases |
| Anything else | the next patch with a suffix, 0.3.1-SNAPSHOT
|
https://repo.onelitefeather.dev/snapshots |
The two version strings are the values at ca79507 and are illustrations of the mechanism rather
than a statement about what the repositories hold today; the authoritative value is the
version = … line of the root build.gradle.kts, which Release Please rewrites.
.github/workflows/release-please.yml holds both publish jobs. They hang off the same
release_created output with opposite conditions, so a push publishes a release or a snapshot and
never both. A second workflow on push cannot see whether a release was cut and would double-publish.
The snapshot version is derived inside the build rather than passed in, because a -Pversion=…
would be overwritten by the version = … assignment that runs after the property is read.
-Psnapshot instead makes the root build bump the patch of the released version and append
-SNAPSHOT; the publishing block already picks its endpoint from that string. The flag reaches
Gradle through the build-task and publish-task inputs of the reusable workflow, which are handed
to ./gradlew verbatim — it offers no input for properties or environment. Check the result with
./gradlew -Psnapshot properties | grep '^version:'.
Both endpoints are public, so a consumer of an artefact needs no credentials. Both exist on the
Reposilite instance and both have been written to: /releases served 0.2.1 of falco-anvil and
falco-light, the two modules published at that time, and /snapshots served 0.2.2-SNAPSHOT, put
there by the first push after that release. That was checked once, by hand, at the time; it is not
verifiable from this repository and no later check is recorded. falco-instance shipped in 0.3.0
and falco-bom was added after it was cut, so the set of published coordinates has grown since that
check.
.github/pull_request_template.md
is the form a pull request opens with, and it is the shortest statement of what review looks for.
Four of its checks decide most of the outcome.
-
The title of the pull request is the Conventional Commit. It becomes the squash-commit message,
and Release Please derives the next version and the changelog entry from it, by the mechanism under
Releasing and snapshots. The template names four scopes —
(anvil),(light),(instance)and(map)— which is one more than Conventions above lists;falco-instanceis the module the fourth one names. A breaking change needs a!or aBREAKING CHANGE:footer. -
A test was written first and watched fail, package-private, named
test<What><Expectation>, with plain JUnit assertions. That is the same rule Conventions states, restated as a checkbox a reviewer ticks. -
The concurrency section is filled in or deleted. It asks which state the change adds or shares
and what guards it, and it asks for a
*ConcurrencyTestwherever shared state is touched. The template gives its own reason: every defect this project has found in its own code so far was a race that failed silently. - The measurements section is filled in or deleted. It asks for JMH figures at the configured forks and iterations rather than a smoke run, with the error margins, the machine, the JVM and the thread count named — the same fields every provenance line in Measured Results carries.
.github/workflows/build-pr.yml
is what then runs on the branch. It is a thin caller of the shared
OneLiteFeatherNET/workflows/.github/workflows/gradle-build-pr.yml job at v2.4.0, pinned to
Java 25 on Temurin with run-tests: true, so a pull request is checked by the same build the first
command under Working on this runs locally. A second workflow,
close_invalid_prs.yml, calls the organisation's close-invalid-prs job when a pull request is
opened.
Review ownership is in .github/CODEOWNERS. Every path is owned by
@OneLiteFeatherNET/falco-maintainers; the root build scripts, the Gradle wrapper, the Release
Please files, CHANGELOG.md and .github/ itself are listed a second time, so that widening the
default owner later cannot silently widen who approves a release.
- The versions in Environment are declared in
settings.gradle.ktsfor the version catalogue and the seven modules, inbuild.gradle.ktsfor the toolchain, the release target and the singleversion = …line, and ingradle/wrapper/gradle-wrapper.propertiesfor the Gradle version. Which of them are pinned here and which are resolved through a BOM is the Pinned here column of that table, and the BOM side is Dependency Management. - Both publish jobs hang off
.github/workflows/release-please.yml. What the release configuration declares and how the snapshot version is derived inside the build is Versioning and Releases; which modules publish what, and howfalco-bomdiffers from the other two kinds of project, is Publishing. - Building the benchmarks is one of the commands under Working on this. Running them, and what a result of the suite can and cannot mean, is Benchmarking; the two demo servers the last two commands start are Benchmarks and Demo.
- The state of the project the conventions above were arrived at in — the structural facts, the decisions, the defects and the open items — is Project Status, and the tables it used to carry are Measured Results.
The measured tables are collected on Measured Results, and a correction to one
is made there first; a page that carries one of its own says so where the table stands.
What the ± after a JMH mean covers is stated once, in Rationale: Measurement.
Wiki home · Repository · README and quick start · API documentation · Issues · Licence: AGPL-3.0
Start here
- Quick start (README)
- Installation
- Anvil Chunk Loader
- Light Engine
-
Rationale: Instances and Chunks — the third module,
falco-instance
The measured record
- Measured Results — every measured table, with the run behind each one
- Benchmarking
- Project Status
- Rationale: Measurement
Why it is built this way
-
Rationale — the index for the five rationale pages
-
Research — the index for the investigations
the six
- Exception Hierarchy
- Instance Container
- Light Engine
- Shared Instances and Batches
- Instance Performance
- Fluent API — a record, not a reference
Working on the build
-
Contributing — what a change is built, tested and released with
-
Build Setup — the build wiring, and the index for the six pages behind it