Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
3fda32f
Major refactor of world, dimension, and chunk
NotStirred Jul 26, 2026
b7b0f7c
Basics of WorldFormat interface
NotStirred Jul 26, 2026
7e899da
Replace all world loading with worldformat
NotStirred Aug 20, 2025
2a58cab
Make WorldFormats registerable
NotStirred Jun 27, 2026
84e3a01
Rename MC_ classes to Java_
NotStirred Jun 27, 2026
23fe79e
Create HeightRange and use it in place of the awkward IntIntPair
NotStirred Jun 28, 2026
5bed5f4
Various method renames
NotStirred Jun 28, 2026
9e1c958
Move player data timestamp into JavaWorld
NotStirred Jul 26, 2026
6a65f44
MC->Java rename misc. cleanup
NotStirred Jun 28, 2026
bf72013
Add more detailed javadoc to WorldFormat apis
NotStirred Jun 28, 2026
aca6bb3
Move isWorldDirectory into JavaWorldFormat
NotStirred Jun 30, 2026
f7af0a2
Make WorldFormat method arguments NotNull
NotStirred Jun 30, 2026
73032d2
Adjust WorldFormat Javadoc
NotStirred Jul 8, 2026
ea1dfd9
Refactor World metadata into World.Info to avoid World object creation.
NotStirred Jul 26, 2026
133ee52
Create a single place for all chunky thread/executors to be registered
NotStirred Jul 8, 2026
30f3aa0
Fix race between joinAll and extremely lately added threads/executors
NotStirred Jul 11, 2026
c675ace
Make joinAll not synchronized
NotStirred Jul 13, 2026
1d166b1
Return whether all threads were joined from joinAll methods
NotStirred Jul 13, 2026
63367be
Add Chunky's ForkJoinPool to ChunkyThread
NotStirred Jul 13, 2026
f5d4d13
Change ExecutorService thread factory
NotStirred Jul 13, 2026
7163545
Add PluginApi to relevant ChunkyThread methods
NotStirred Jul 13, 2026
297b535
Add shutdown hook to handle early System.exit()
NotStirred Jul 13, 2026
7f0c661
Put interruptAndJoinAll in a finally block
NotStirred Jul 13, 2026
22330c6
Switch back to ConsoleReceiver on UI stop
NotStirred Jul 24, 2026
afb0947
Move the shutdown hook out of ChunkyThread, now managed by Chunky itself
NotStirred Jul 24, 2026
f20b005
Remove PluginApi from joinAll
NotStirred Jul 24, 2026
e69129b
Refactor ChunkyThread joinAll to give stronger guarantees
NotStirred Jul 24, 2026
f6acc0b
Remove jank in PluginManager
NotStirred Jul 23, 2026
5812537
Remove unnecessary chunky.plugins.maxLoadCycles jvm arg.
NotStirred Jul 23, 2026
a1b164d
Implement plugin shutdown
NotStirred Jul 24, 2026
c5b971d
Update github actions.
leMaik Jul 25, 2026
d3eb7f6
Update to java 25.
leMaik Jul 25, 2026
69689c0
Update gradle for java 25, use java 25 for testing too.
leMaik Jul 25, 2026
6e26c9c
Remove obsolete names from setup-java and setup-gradle actions.
leMaik Jul 25, 2026
091fe65
Update JaCoCo for Java 25 support.
leMaik Jul 25, 2026
559a6b7
Use JUnit 5 for the launcher, too.
leMaik Jul 25, 2026
eaf263c
Copy versioned chunky-core.jar into build directory and fix generatin…
leMaik Jul 28, 2026
2a9bbb3
Merge branch 'feature/world_format' into feature/bedrock.new
NotStirred Jul 29, 2026
91adeb8
Merge branch 'fix/non_daemon_threads' into feature/bedrock.new
NotStirred Jul 29, 2026
4fb0cf5
Merge branch 'feature/plugin_shutdown' into feature/bedrock.new
NotStirred Jul 29, 2026
665f374
bedrock: Loading worlds
NotStirred Jul 26, 2026
e07dd69
bedrock: Implement map surface layer map view
NotStirred Jun 24, 2026
a574502
bedrock: Set chunks to empty if they don't exist.
NotStirred Jun 24, 2026
9a53a54
bedrock: Optimise reads for chunky's general case
NotStirred Jun 24, 2026
ad52d6a
bedrock: Fix incorrect coordinates for chunks in the map view
NotStirred Jun 26, 2026
77fd1d9
bedrock: Parse biomes and heightmap data (Data3D)
NotStirred Jun 27, 2026
5be40fc
bedrock: Fix being able to select empty chunks in the map
NotStirred Jun 27, 2026
dcbe84a
bedrock: Fix incorrectly parsing empty subchunks
NotStirred Jun 27, 2026
ae637f6
bedrock: Prevent opening the same DB in two places at once
NotStirred Jun 27, 2026
5bc88f6
bedrock: Always set BiomeData when loading chunks
NotStirred Jun 28, 2026
e52ad65
bedrock: Switch to a Plugin, properly close DBs on plugin shutdown.
NotStirred Jul 2, 2026
501f7ea
bedrock: Use per-DBRef arenas instead of incorrect auto usage
NotStirred Jul 11, 2026
ad02e31
bedrock: Remove manual db closure
NotStirred Jul 11, 2026
b98bc38
bedrock: Null dbRef fields to avoid extremely rare double free
NotStirred Jul 11, 2026
438ad37
bedrock: Log DB opens and closes
NotStirred Jul 11, 2026
9cc28e6
bedrock: Add DBRef javadoc
NotStirred Jul 11, 2026
9f4de5f
REMOVE ME BEFORE MERGE: don't cache snapshot jars
NotStirred Jul 26, 2026
1e9b5cb
bedrock: Fix incorrect handling of overlapping subchunk storages
NotStirred Jul 30, 2026
5ab4b1c
bedrock: Support increased world height range -64/320
NotStirred Jul 30, 2026
5eb4f7e
bedrock: Support subchunk version 8
NotStirred Jul 30, 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: 6 additions & 8 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
java-version: '25'
- uses: gradle/actions/setup-gradle@v6
with:
cache-read-only: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/chunky-2.4.x' }}
- name: Grant execute permission for gradlew
Expand All @@ -46,12 +44,12 @@ jobs:
;;
esac
- name: Upload build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Chunky Build
path: build/installer
- name: Upload build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Chunky Core
path: build/chunky-core-*.jar
83 changes: 56 additions & 27 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
project.version = getVersion()
println "Building version ${project.version}"
def projectVersion = getVersion().toString()
println "Building version ${projectVersion}"

allprojects {
repositories {
mavenCentral()
mavenLocal()
// FIXME @NotStirred: DO NOT RELY ON SNAPSHOT LEVELDB-FFI
maven {
name = "Maven Central SNAPSHOT"
url = "https://central.sonatype.com/repository/maven-snapshots/"
}
}
configurations.configureEach { // FIXME: Remove, this makes gradle never cache snapshot jars (leveldb-ffi snapshots are changing throughout dev)
it.resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
}

Expand All @@ -15,7 +22,7 @@ buildscript {
}
}
dependencies {
classpath 'org.openjfx:javafx-plugin:0.0.13'
classpath 'org.openjfx:javafx-plugin:0.1.0'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.46.0'
}
}
Expand All @@ -33,20 +40,10 @@ subprojects {
java {
toolchain {
// default java version for the project
languageVersion = JavaLanguageVersion.of(17)
}
}
compileTestJava {
// compile tests using more recent features
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(25)
}
}
test {
// run tests using more recent features
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(21)
}
useJUnitPlatform()

// Always run tests, even when nothing changed.
Expand All @@ -55,7 +52,7 @@ subprojects {
finalizedBy jacocoTestReport // report is always generated after tests run (it's very cheap)
}
jacoco {
toolVersion = "0.8.11"
toolVersion = "0.8.15"
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
Expand Down Expand Up @@ -113,19 +110,37 @@ defaultTasks 'release'

task releaseVersion {
doLast {
tryCommand([ 'git', 'tag', '-a', "${project.version}", '-m', "Version ${project.version}" ], true)
tryCommand([ 'git', 'tag', '-a', "${projectVersion}", '-m', "Version ${projectVersion}" ], true)
}
}

task prepareReleaseLibraries {
dependsOn ':chunky:copyExternalDependencies'
outputs.upToDateWhen { false }

doLast {
def libDir = file('chunky/lib')
libDir.mkdirs()
copy {
from project(':chunky').tasks.named('copyExternalDependencies').get().outputs.files
into libDir
}
}
}

task versionInfo(type: JavaExec) {
dependsOn 'copyArtifacts'
dependsOn 'prepareReleaseLibraries'
outputs.upToDateWhen { false }

outputs.files file("build/chunky-${project.version}.jar")
description 'Writes build/chunky-VERSION.jar, latest.json and updates chunky-core-VERSION.jar/version.json'
outputs.file(layout.buildDirectory.file("chunky-${projectVersion}.jar"))

description = 'Writes build/chunky-VERSION.jar, latest.json and updates chunky-core-VERSION.jar/version.json'

classpath = project(':releasetools').sourceSets.main.runtimeClasspath
mainClass.set('releasetools.ReleaseBuilder')
args "${project.version}", "release_notes-${project.version}.txt"

args projectVersion, "release_notes-${projectVersion}.txt"
}

task release {
Expand All @@ -138,30 +153,34 @@ task release {
destinationDirectory.mkdirs()
file("./latest.json").renameTo("${destinationDirectory}/latest.json")
fileTree(buildDir).matching {
include "*-${project.version}.*"
include "*-${projectVersion}.*"
}.each {
it.renameTo("${destinationDirectory}/${it.name}")
}
}
}

def launcherArchives = project(':launcher').configurations.archives

task buildReleaseJar(type: Jar) {
dependsOn ':launcher:assembleDist'
dependsOn 'prepareReleaseLibraries'
dependsOn 'versionInfo'

archiveFileName = "chunky-${project.version}.jar"
archiveFileName = "chunky-${projectVersion}.jar"
destinationDirectory = file('build/installer')
manifest {
attributes('Main-Class': 'se.llbit.chunky.launcher.ChunkyLauncher')
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

into('lib') {
from fileTree('chunky/lib').include('*.jar')
from file("build/chunky-core-${project.version}.jar")
from file("build/chunky-core-${projectVersion}.jar")
}

from {
project(':launcher').configurations.archives.allArtifacts.files.collect {
launcherArchives.allArtifacts.files.collect {
zipTree(it)
}
}
Expand All @@ -170,10 +189,20 @@ task buildReleaseJar(type: Jar) {
rename "latest.json", "version.json"
}

task copyArtifacts(type: Copy) {
task copyArtifacts {
dependsOn subprojects.jar
from subprojects.jar
into buildDir
dependsOn ':chunky:jar'
outputs.upToDateWhen { false }

doLast {
def sourceJar = project(':chunky').tasks.named('jar').get().archiveFile.get().asFile
def rootJar = file("build/chunky-core-${projectVersion}.jar")
copy {
from sourceJar
into rootJar.parentFile
rename { rootJar.name }
}
}
}

/** Helper function to run a command. Returns the command output if the command succeeded. */
Expand Down
1 change: 1 addition & 0 deletions chunky/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/bin/
/build/
/lib/
/src/gen-res/
72 changes: 44 additions & 28 deletions chunky/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ apply plugin: 'application'
apply plugin: 'maven-publish'
apply plugin: 'org.openjfx.javafxplugin'

mainClassName = 'se.llbit.chunky.main.Chunky'
archivesBaseName = 'chunky-core'
application {
mainClass = 'se.llbit.chunky.main.Chunky'
}

base {
archivesName = 'chunky-core'
}

configurations {
implementation.extendsFrom configurations.jsonlib
Expand All @@ -25,11 +30,13 @@ dependencies {
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.lz4:lz4-java:1.8.0'
implementation 'org.apache.maven:maven-artifact:3.9.9'
implementation 'io.github.notstirred:leveldb-ffi:0.1.0-SNAPSHOT'
implementation 'org.cloudburstmc:nbt:3.0.0.Final'
implementation project(':lib')
}

javafx {
version = '17.0.11'
version = '25'
configuration = 'implementation'
modules = ['javafx.base', 'javafx.controls', 'javafx.fxml']
}
Expand All @@ -52,7 +59,7 @@ jar {
zipTree(it)
}
manifest {
attributes('Main-Class': mainClassName)
attributes('Main-Class': application.mainClass)
}
into('se/llbit/chunky/main') {
from file("src/gen-res/Version.properties")
Expand All @@ -78,25 +85,35 @@ sourceSets {

processResources.dependsOn 'updateVersionString'

def projectVersion = providers.provider {
version.toString()
}

task updateVersionString {
description 'Store the current version string in src/gen-res/Version.properties'
description = 'Store the current version string in src/gen-res/Version.properties'

def versionFile = layout.projectDirectory.file('src/gen-res/Version.properties')

outputs.upToDateWhen {
def props = new Properties()
def output = file('src/gen-res/Version.properties')
if (output.isFile()) {
output.withInputStream { stream -> props.load(stream) }
if (versionFile.asFile.isFile()) {
versionFile.asFile.withInputStream { stream ->
props.load(stream)
}
}
props['version'] == project.version
props['version'] == projectVersion.get()
}

doLast {
file('src/gen-res').mkdirs()
def date = new Date()
def versionFile = file('src/gen-res/Version.properties')
ant.propertyfile(file: versionFile) {
entry(key: 'version', value: project.version)
entry(key: 'gitSha', value: tryCommand(['git', 'rev-parse', 'HEAD']).trim())
versionFile.asFile.parentFile.mkdirs()

def gitSha = rootProject.tryCommand(
['git', 'rev-parse', 'HEAD']
).trim()

ant.propertyfile(file: versionFile.asFile) {
entry(key: 'version', value: projectVersion.get())
entry(key: 'gitSha', value: gitSha)
}
}
}
Expand All @@ -112,12 +129,13 @@ task sourcesJar(type: Jar) {
}

task copyExternalDependencies(type: Copy) {
into "${buildDir}/${libsDirName}"
into layout.buildDirectory.dir("libs")
from configurations.externalDependencies
}

artifacts {
archives javadocJar, sourcesJar
tasks.named("assemble") {
dependsOn(javadocJar)
dependsOn(sourcesJar)
}

publishing {
Expand All @@ -129,7 +147,7 @@ publishing {
packaging = "jar"
description = "Minecraft mapping and rendering tool"
url = "http://chunky.llbit.se"
artifactId = archivesBaseName
artifactId = base.archivesName
version = "2.5.0-SNAPSHOT"

licenses {
Expand All @@ -156,22 +174,20 @@ publishing {

// fix dependency scopes (see https://discuss.gradle.org/t/maven-publish-plugin-generated-pom-making-dependency-scope-runtime/7494/9)
// and filter dependencies
def implementationDependencies = configurations.implementation.allDependencies
publishing.publications.all {
pom.withXml {
asNode().dependencies.'*'.findAll() {
it.scope.text() == 'runtime' && project.configurations.implementation.allDependencies.find { dep ->
asNode().dependencies.'*'.findAll {
it.scope.text() == 'runtime' &&
implementationDependencies.find { dep ->
dep.name == it.artifactId.text()
}
}.each() {
}.each {
if (it.groupId.text() == "org.openjfx") {
// remove javafx dependencies for now (maybe make them optional in the future?)
it.parent().remove(it)
// it.appendNode('optional', 'true')
} else if (it.groupId.text() == "se.llbit") {
// se.llbit dependencies are included in chunky-core
it.parent().remove(it)
} else {
// everything else is a dependency as usual
it.scope*.value = 'compile'
}
}
Expand All @@ -181,8 +197,8 @@ publishing {

repositories {
maven {
name 'Build'
url layout.buildDirectory.dir('maven')
name = 'Build'
url = layout.buildDirectory.dir('maven')
}
}
}
14 changes: 14 additions & 0 deletions chunky/src/java/se/llbit/chunky/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package se.llbit.chunky;

import se.llbit.chunky.main.Chunky;
import se.llbit.util.concurrent.ChunkyThread;

/**
* The plugin interface for Chunky plugins.
Expand All @@ -33,4 +34,17 @@ public interface Plugin {
* @param chunky Chunky instance which the plugin should attach to
*/
void attach(Chunky chunky);

/**
* Called when chunky shuts down, allowing the plugin to close critical resources. Most plugins do not need to do
* anything here.
*
* <p>This function will be called after all {@link ChunkyThread}s have shut down. Chunky's UI thread may still
* be running.</p>
* <p>This method will not be called if any {@link ChunkyThread} does not shut down within its given time limit</p>
* <p>This method may not be called if chunky terminates in a non-normal way, such as through {@link Runtime#halt},
* the user killing the process (<code>SIGKILL</code> & <code>TerminateProcess</code>), or an error within a native
* function.</p>
*/
default void shutdown(Chunky chunky) { }
}
Loading
Loading