Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9aad698
feat(anvil): add region file layer for the new chunk loader
TheMeinerLP Jul 30, 2026
fdd6d81
feat(anvil): add a strict access facade for adventure nbt
TheMeinerLP Jul 30, 2026
69f81be
feat(anvil): add palette data and loader diagnostics
TheMeinerLP Jul 30, 2026
3a46365
feat(anvil): add the multithreaded anvil chunk loader
TheMeinerLP Jul 30, 2026
c5a0f20
feat(map): allow a map provider to choose its chunk loader
TheMeinerLP Jul 30, 2026
0f50403
chore(anvil): mark the anvil loader as experimental
TheMeinerLP Jul 30, 2026
391ab22
fix(anvil): store block entities at their world position
TheMeinerLP Jul 30, 2026
fe13233
feat(anvil): resolve block handlers and release region files on unload
TheMeinerLP Jul 30, 2026
633ec87
docs: write up the three research investigations
TheMeinerLP Jul 30, 2026
9870504
feat(light): add a section light propagation
TheMeinerLP Jul 31, 2026
c31a26e
feat(light): apply the light engine to chunks of a running server
TheMeinerLP Jul 31, 2026
2d0fd89
feat(light): add sky light, chunk borders and incremental updates
TheMeinerLP Jul 31, 2026
aaf1765
fix(light): grow the propagation queue and settle the border exchange
TheMeinerLP Jul 31, 2026
c27c29e
test(anvil): add concurrency stress tests and JMH benchmarks
TheMeinerLP Jul 31, 2026
ac16430
perf(anvil): lower the compression level and make it selectable
TheMeinerLP Jul 31, 2026
53ee7e8
perf(light,anvil): skip the per position table for uniform sections
TheMeinerLP Jul 31, 2026
084f0d0
docs: summarise the state of the branch
TheMeinerLP Jul 31, 2026
c1afaa5
docs: make the status file enough to rebuild the context from
TheMeinerLP Jul 31, 2026
200618a
fix(light): build a propagator per call in the chunk light service
TheMeinerLP Jul 31, 2026
5104fb0
fix(anvil): make a lock free region read return a state that existed
TheMeinerLP Jul 31, 2026
12a0b41
fix(anvil): keep a region file open while a thread is using it
TheMeinerLP Jul 31, 2026
de6f830
fix(anvil): reject loads and saves on a closed loader
TheMeinerLP Jul 31, 2026
72baef5
refactor(anvil): drop the region file handle check that lost its caller
TheMeinerLP Jul 31, 2026
37544a3
docs: record the five races and what is still open after them
TheMeinerLP Jul 31, 2026
d22760d
test(jmh): measure the loader head to head against the one Minestom s…
TheMeinerLP Jul 31, 2026
f9ed087
docs(anvil): show where the loader is ahead, and where it is not
TheMeinerLP Jul 31, 2026
f6cf4f5
docs: add line charts and structural diagrams for the measured compar…
TheMeinerLP Jul 31, 2026
44bed0d
docs(benchmarks): list the comparison benchmarks and correct the serv…
TheMeinerLP Jul 31, 2026
78e196c
fix(anvil): keep the external chunk file replaceable while a reader h…
TheMeinerLP Jul 31, 2026
bec8b67
ci: keep the test reports of a failed build
TheMeinerLP Jul 31, 2026
224b546
docs: record the light algorithm research in STATUS.md
TheMeinerLP Jul 31, 2026
69381af
perf(light): build the opacity table without allocating per block
TheMeinerLP Jul 31, 2026
0e8fbb5
test(jmh): measure the light engines on mixed source brightness
TheMeinerLP Jul 31, 2026
f474139
docs: reference the Aves sources by member instead of by line
TheMeinerLP Jul 31, 2026
eec46ee
docs: bring the light engine numbers in STATUS.md up to date
TheMeinerLP Jul 31, 2026
6f55ac4
docs: bring the light numbers up to the optimised engine
TheMeinerLP Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/build-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,16 @@ jobs:
distribution: temurin
java-version: 25
- name: Build on ${{ matrix.os }}
run: ./gradlew clean build
run: ./gradlew clean build
# Gradle's console summary names the failing test and the exception type, but not the
# message, the path or the stack trace. For a failure that only happens on one operating
# system, that is the difference between reading the cause and guessing at it.
- name: Upload test reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.os }}
path: |
build/reports/tests/
build/test-results/
retention-days: 7
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ bin/

# OS-spezifisch
.DS_Store
Thumbs.db
Thumbs.db

# Serena (MCP code navigation)
.serena/
619 changes: 619 additions & 0 deletions STATUS.md

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
`java-library`
`maven-publish`
jacoco
alias(libs.plugins.jmh)
}

group = "net.theevilreaper"
Expand All @@ -25,14 +26,52 @@ dependencies {
implementation(libs.slf4j.api)

compileOnly(libs.adventure)
compileOnly(libs.adventure.nbt)
compileOnly(libs.annotations)
compileOnly(libs.minestom)

testImplementation(libs.adventure)
testImplementation(libs.adventure.nbt)
testImplementation(libs.annotations)
testImplementation(libs.minestom)
testImplementation(libs.cyano)
testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.platform.launcher)
testRuntimeOnly(libs.junit.jupiter.engine)

// The benchmarks live in their own source set (src/jmh/java). Nothing declared here reaches the
// main or the test classpath, so the published library never carries a jmh dependency.
jmhImplementation(platform(libs.mycelium.bom))
jmhImplementation(platform(libs.adventure.bom))
jmhImplementation(libs.adventure.nbt)
jmhImplementation(libs.annotations)
jmhImplementation(libs.jmh.core)
// Minestom is needed only by the comparison benchmark, which measures our light engine against
// the one the server ships with. It stays out of every other benchmark on purpose, so those
// measure this library and not a registry lookup.
jmhImplementation(libs.minestom)
jmhImplementation(libs.fastutil)
// No jmh annotation processor is declared on purpose. The plugin already generates the harness
// classes with its bytecode generator, and declaring the processor as well makes both of them
// emit the same classes, which leaves the jar with two copies of every benchmark.
}

jmh {
jmhVersion.set(libs.versions.jmh)
// The tests of this project need a Minestom server, which a benchmark jar cannot start.
includeTests.set(false)
resultFormat.set("JSON")
resultsFile.set(layout.buildDirectory.file("reports/jmh/results.json"))
humanOutputFile.set(layout.buildDirectory.file("reports/jmh/human.txt"))

// A full run takes the better part of an hour, so a single benchmark has to be reachable
// without editing this file.
// Usage: ./gradlew jmh -Pjmh.include='BitPackerBenchmark.pack'
val include = providers.gradleProperty("jmh.include").orNull

if (include != null) {
includes.set(listOf(include))
}
}

tasks {
Expand All @@ -41,6 +80,18 @@ tasks {
options.release.set(25)
}

compileJmhJava {
options.encoding = "UTF-8"
}

// The benchmarks are compiled by a normal build but never executed by one. A run takes the
// better part of an hour and its numbers are far too noisy on a shared runner to gate anything
// on, while a benchmark that stopped compiling after a refactoring should fail like any other
// source set.
check {
dependsOn(compileJmhJava)
}

jacocoTestReport {
dependsOn(rootProject.tasks.test)
reports {
Expand All @@ -52,6 +103,10 @@ tasks {
test {
finalizedBy(rootProject.tasks.jacocoTestReport)
useJUnitPlatform()
// The chunk loader tests allocate payloads of about one mebibyte to cover the external
// chunk file path. Without an explicit heap the worker can die while other build tasks
// run in parallel, which surfaces as an EOFException instead of a test failure.
maxHeapSize = "1g"
jvmArgs("-Dminestom.inside-test=true")
testLogging {
events("passed", "skipped", "failed")
Expand Down
Loading
Loading