- Java 99.5%
- JavaScript 0.2%
- Kotlin 0.2%
The previous README was upstream FAWE's stock generic one (project blurb, feature list, links to the Bukkit/CurseForge distribution) - said nothing about this being a Fabric-specific fork, what changed here, or how to actually build it (which has a real two-JDK gotcha: fabric-loom 1.14.x needs a Java 21+ runtime to run Gradle at all, while the actual compiled output targets Java 17). Replaced with fork-specific docs: what this fork is and why it exists, the full Java 21->17 retargeting changelog from this session, concrete build instructions, an updating-from-upstream section, and known limitations. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| .github | ||
| .idea | ||
| build-logic | ||
| contrib/craftscripts | ||
| gradle | ||
| worldedit-bukkit | ||
| worldedit-cli | ||
| worldedit-core | ||
| worldedit-fabric | ||
| worldedit-forge | ||
| worldedit-libs | ||
| worldedit-mod | ||
| worldedit-sponge | ||
| .editorconfig | ||
| .git-blame-ignore-revs | ||
| .gitattributes | ||
| .gitconfig | ||
| .gitignore | ||
| Annotation-Explanation.adoc | ||
| build.gradle.kts | ||
| COMPILING.adoc | ||
| crowdin.yml | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| HEADER.txt | ||
| Jenkinsfile | ||
| LICENSE.txt | ||
| NOTICE.txt | ||
| README.md | ||
| settings.gradle.kts | ||
FAWE for Fabric 1.20.4 (MTR France fork)
This is a fork of Plaaasma/FabricAsyncWorldEdit,
itself a community continuation that ports FastAsyncWorldEdit's
real engine (worldedit-core) to the Fabric platform. This is not a rewrite from
scratch — it reuses upstream FAWE's actual codebase plus a worldedit-fabric
platform module, the same way upstream itself has worldedit-bukkit,
worldedit-cli, etc.
Why this exists
FAWE only has an officially maintained Bukkit/Paper (and CLI) build upstream —
there is no maintained official Fabric release. The MTR France server (Fabric
1.20.4) needs fast, async world editing to build large rail infrastructure at
scale, and vanilla WorldEdit-Fabric (7.3.0, kept as a reference/fallback at
mods_backup/worldedit-mod-7.3.0.jar on the server) doesn't have FAWE's
performance or feature set. Rather than write a Fabric port from zero, this fork
continues Plaaasma's existing work (which had already done the hard part: real
block placement mapping, permission checks, command forwarding, startup wiring
between FAWE's engine and Fabric's API) and gets it working correctly for our
specific target instead of abandoning that work.
For what FAWE itself actually is and does (the 200+ commands, brushes, masks, CFI, clipboard web integration, etc.), see upstream's own README and wiki — this fork changes nothing about FAWE's actual editing functionality, only what platform/Java version it runs on.
Status as of 2026-07-31
- Branch name (
fabric-1.20.1) is historical/stale from before this fork's own version catalog was updated — despite the name,gradle/libs.versions.tomlis pinned to MC 1.20.4 / Fabric Loader 0.19.3 / Fabric API 0.97.3+1.20.4, matching the actual MTR France server. Don't rename the branch casually; checkgradle/libs.versions.tomlfor ground truth on what version this actually targets, not the branch name. - Builds cleanly and produces a correctly Java-17-bytecode jar (see "What changed" below). Deployed to the MTR France server and its client modpack.
- Not yet actually tested in-game. Only compile-time and
javap-verified bytecode-version checks have been done so far. Test//wand,//set,//copy///paste,//undo, and schematic load/save on a disposable world (world_flatcontinents_testorworld_flathills_teston the server) before trusting this for real construction.
What changed in this fork (2026-07-31 session)
The jar previously deployed to the server (worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT.jar)
silently contained Java 21 bytecode (class file version 65) despite its name
claiming 1.20.4 compatibility. This crashed every normal Java-17 Minecraft client
at bootstrap (UnsupportedClassVersionError, thrown while loading WorldChunk
right after this mod's mixins merged in) — the reason it went unnoticed for over
a week is that the MTR France server itself happens to run Java 21
(ghcr.io/pterodactyl/yolks:java_21 Docker image), so it worked there while
silently breaking every client.
Root cause: build-logic/src/main/kotlin/buildlogic.common.gradle.kts hardcodes
a project-wide JavaLanguageVersion.of(21) toolchain, inherited from upstream
FAWE's own Bukkit/Paper build (which genuinely needs 21 for newer MC versions).
Nobody had overridden this for the Fabric module specifically.
The fix, and everything that cascaded from it:
- Toolchain override, in
worldedit-core/build.gradle.ktsandworldedit-fabric/build.gradle.ktsonly (not globally — other platforms in this fork, bukkit/forge/sponge/cli, are irrelevant to us and left untouched):java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } buildlogic.common-java.gradle.ktscompiler args: it also force-setsoptions.release.set(21)and adds-Xlint:-this-escape(a lint category that only exists on JDK 21+ javac — passing it to a 17 javac is a hard "invalid flag" error, not just a warning). Overrode both modules'compileJava/compileTestJavatasks to setrelease.set(17)and rebuildcompilerArgswithout that flag. Kept--add-modules=jdk.incubator.vector— that module is available since 17 (just incubating), it wasn't the problem.buildlogic.libs.gradle.kts(shared by everyworldedit-libs:*submodule) hardcoded a Gradle variant metadata attributeTargetJvmVersion=21. This isn't about real bytecode — those submodules just shade third-party jars via ShadowJar, no first-party compilation happens there — so dropping it to 17 was a pure metadata fix, not a functional risk.- Three external dependencies were themselves Java-21-only and had to be
pinned back to their last Java-17-compatible release (found by checking each
candidate version's Gradle Module Metadata
.modulefile fororg.gradle.jvm.version):plotsquared-core7.5.11→7.3.8—compileOnly, an optional Bukkit-only protection-plugin integration, irrelevant to Fabric.lin-bus(-tree/-common/-stream/-format-snbt/-bom)0.2.0→0.1.0— not optional, this is FAWE's core NBT/tag library, used pervasively. This one needed real source-level API-compat fixes (see below), not just a version bump.fabric-permissions-api0.6.1→0.3.3—modCompileOnly, an optional LuckPerms-style permission check.
- Real Java 21 language/API usage in FAWE's own source that simply doesn't
compile on 17, rewritten:
- Switch pattern matching (
case Type name -> ..., a preview feature on 17, finalized in 21) → plaininstanceofchains, inSimdSupport.java,MutatingOperationTransformHolder.java,AbstractPlayerActor.java,FabricTransmogrifier.java. - One record pattern (
instanceof FacingTagData(String a, ...)) → a plaininstanceofbinding plus accessor calls, inExtentEntityCopy.java. Thread.ofVirtual()(virtual threads, finalized in 21) → a plain daemonThread, inChangeExchangeCoordinator.java— only ever one such thread per instance, virtual threads buy nothing here.- The
ForkJoinWorkerThread(ThreadGroup, ForkJoinPool, boolean)3-arg constructor doesn't exist pre-21; on 17 only the 1-argprotected ForkJoinWorkerThread(ForkJoinPool)constructor is accessible outsidejava.util.concurrent— fixed inFaweForkJoinThread.java. List.getLast()(SequencedCollection, JDK 21) →list.get(list.size() - 1), inRandomTransformParser.java.Math.ceilDiv(JDK 18+) → the classic-Math.floorDiv(-a, b)ceiling-division trick (works since Java 8), inMathMan.java.
- Switch pattern matching (
- The
lin-busdowngrade needed real API-compat fixes, not just a version bump:LinReadOptions(a legacy-UTF8-decoding option class used for reading old MCEdit/Sponge-v1/v2 schematics) doesn't exist at all in0.1.0— no options-accepting overload ofLinBinaryIO.read/readUsingexists in that version either. Dropped the option entirely inBuiltInClipboardFormat.java(3 call sites). Consequence: very old schematics with non-standard NBT string encoding may fail to import; normal/modern schematics are unaffected.LinCompoundTag.value()returns a wildcard-boundedMap<String, ? extends LinTag<?>>in0.1.0, simplified toMap<String, LinTag<?>>in later versions Java won't let you assign one to the other directly. Widened three local variable declarations to match (all read-only usage, so semantically safe) inBaseEntity.java,BlockTransformExtent.java,MinecraftStructure.java.
Building this fork
You need two JDKs, not one
This is the part that will trip you up if you skip it. Two separate Java version requirements are in play, for two different reasons:
- fabric-loom 1.14.x's own build tooling requires a Java 21+ runtime just to
run Gradle at all (unrelated to what Java version your code targets — the
loom plugin's own compiled classes need a JVM that can load them). If you only
have a Java 17 JDK, configuring the project will fail immediately with
Dependency requires at least JVM runtime version 21. - The actual compiled output (
worldedit-core,worldedit-fabric) targets Java 17, per the toolchain overrides described above, because that's what Fabric Loader 0.19.3 / MC 1.20.4 clients actually run.
Gradle's toolchain resolution handles this split automatically if it can find both JDKs — you just need to tell it where they are.
- Install a JDK 21 (a full JDK, not just a JRE — you need
javac; a Temurin/Adoptium build works fine, get one from adoptium.net if you don't have one) and a JDK 17 (same source). - Point Gradle at both in
gradle.properties(already set up in this repo, but verify the paths match your machine):org.gradle.java.installations.paths=C:/path/to/jdk-17,C:/path/to/jdk-21 org.gradle.java.installations.auto-detect=true - Launch Gradle itself with the Java 21 JDK as
JAVA_HOME(this is what satisfies loom's own runtime requirement — Gradle's toolchain feature then separately picks Java 17 for the actualworldedit-core/worldedit-fabriccompilation, because that's what theirbuild.gradle.ktsfiles request):
On Windows PowerShell:# from a shell where JAVA_HOME can be set for this command only JAVA_HOME=/path/to/jdk-21 ./gradlew :worldedit-fabric:build$env:JAVA_HOME = "C:\path\to\jdk-21"; .\gradlew.bat :worldedit-fabric:build
Building the whole multi-module project (./gradlew build with no target) will
also try to build worldedit-bukkit/worldedit-forge/worldedit-sponge/etc.,
which this fork doesn't maintain and doesn't need — just build the one module we
actually ship:
JAVA_HOME=/path/to/jdk-21 ./gradlew :worldedit-fabric:build
Output
The file to actually deploy is:
worldedit-fabric/build/libs/worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT-dist.jar
Not the plain worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT.jar in the same
folder — that one has no bundled dependencies and won't run standalone. The
-dist.jar is the shaded-and-remapped artifact (via shadowJar +
remapShadowJar), ~14MB, containing worldedit-core's classes plus the runtime
libraries FAWE needs that vanilla/Fabric don't ship (zstd, lz4, parallelgzip,
json-simple, jchronic, snakeyaml, antlr4-runtime, jlibnoise).
Verify the output actually targets Java 17 before trusting it (checks the first
4 bytes after the 0xCAFEBABE magic number — 0x003d = decimal 61 = Java 17;
0x0041 = 65 = Java 21, the bug this fork exists to avoid regressing back into):
unzip -p worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT-dist.jar com/sk89q/worldedit/WorldEdit.class | xxd -l 8 -p
COMPILING.adoc in this repo is upstream's original generic instructions (says
"Java 21", ./gradlew clean build, mentions all four platform modules) — it
predates this fork's retargeting and doesn't reflect the two-JDK setup above.
Treat this README as the accurate one for this fork specifically.
Updating from upstream
Two places changes could come from:
origin— this fork's actual parent, Plaaasma/FabricAsyncWorldEdit. Check it periodically for Fabric-integration fixes (block placement, mixins, command forwarding).git fetch originand diff/merge/cherry-pick as needed — don't blindlygit merge origin/<branch>, since a straight merge would very likely reintroduce the Java 21 toolchain (upstream's ownbuildlogic.commonhasn't been fixed the way ours has) and the dependency versions we downgraded. After merging anything from upstream, re-check:build-logic/src/main/kotlin/buildlogic.common.gradle.ktsline settingJavaLanguageVersion.of(...)— should stay overridden to 17 in our two modules' ownbuild.gradle.kts, but confirm the override still applies cleanly after a merge.gradle/libs.versions.toml— confirmplotsquared,linbus,fabric-permissions-apihaven't been silently bumped back to Java-21-only versions by an upstream merge.
- Upstream FAWE itself
(IntellectualSites/FastAsyncWorldEdit) —
worldedit-coreis shared code; Plaaasma's fork presumably rebases onto FAWE releases periodically. If pulling newer FAWE-core changes directly (rather than through Plaaasma's fork), watch for new Java 21-only syntax/API usage introduced by FAWE's own ongoing modernization (this is exactly what caused the switch-pattern/record-pattern/virtual-thread issues fixed in this session) — there's no reason to expect that trend to stop, since upstream fully supports Java 21+ now.
Known limitations
- Very old MCEdit/Sponge-v1/v2 schematic files using non-standard NBT string
encoding may fail to import (see
LinReadOptionsnote above). Normal/modern schematics (Sponge v3,.schem) are unaffected. - No PlotSquared, WorldGuard-Bukkit, or LuckPerms-native integration on this platform (those are Bukkit-only or pinned to old versions here specifically because they're optional and Java-21-only in their current releases) — not a regression, FAWE-Fabric never had these; just don't expect them.
- Not yet tested in-game (see "Status" above) — treat as unverified for actual world-editing correctness, only verified to build and load without crashing the client/server class loader.
Where this is deployed
- MTR France server:
mods/worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT.jar(the-dist.jarrenamed on deployment) on the Pterodactyl volume. - Client pack:
mods.adlmrl.fr/pack/mods/worldedit-fabric-mc1.20.4-2.15.1-snapshot.pw.toml(packwiz entry,side = "both"), also hosted directly atmods.adlmrl.fr/worldedit-fabric-mc1.20.4-2.15.1-SNAPSHOT.jar.