Gravestone × Sable Compatibility Patch
A minimal patch mod for Minecraft 1.21.1 / NeoForge that fixes gravestone placement when a player dies on a Sable sub-level (e.g. a Create Aeronautics airship). Without this mod, dying mid-flight makes gravestone place its block (and a dirt support block) in the parent world at the player's visible position. The blocks then clip into the airship's collision shape and stall its physics.
With this mod installed, the grave is placed inside the airship's plot area, so it lands on the deck and travels with the airship like any other block on it.
How it works (one paragraph)
Sable stores each sub-level's blocks in a far-away "plot" region of the same
Level. The visible airship position is a logical pose that's applied at render
and collision time only. Gravestone's DeathEvents.playerDeath calls
GraveUtils.getGraveStoneLocation(level, deathPos) with the player's world
position — but that position is empty space, so the search either fails or
places the grave clipping into the airship. This mod uses Mixin Extras'
@WrapOperation to intercept that single call and substitute the player's
position transformed into the sub-level's plot-local frame
(subLevel.logicalPose().transformPositionInverse(playerPos)). Gravestone's
existing search routine then finds the deck above the player's feet and places
the grave correctly inside the contraption. If the player isn't on a sub-level
when they die, the mod is a no-op.
The mod uses Sable Companion rather than depending on Sable directly, so it's safe to ship in packs without Sable (the companion's default implementation just returns null for all sub-level queries → graves behave exactly like vanilla gravestone).
Build
Requires JDK 21.
If you don't already have a Gradle wrapper jar in gradle/wrapper/, bootstrap
one first (one-time, needs any system Gradle ≥ 8.10 — sdk install gradle 8.10,
brew install gradle, apt install gradle, etc.):
gradle wrapper --gradle-version 8.10
Alternatively, copy gradlew, gradlew.bat, and gradle/wrapper/ from any
recent NeoForge 1.21.1 mod template (e.g. the official
NeoForge MDK).
Then build the mod:
./gradlew build
The output jar is at build/libs/gravestone_sable_compat-1.0.0.jar.
If the Modrinth maven can't resolve gravestone-mod for your machine, drop
gravestone-1.21.1-1.0.19.jar (or any 1.21.1 build of gravestone) into a
libs/ folder at the project root, comment out the compileOnly "maven.modrinth:gravestone-mod:..." line in build.gradle, and uncomment the
compileOnly fileTree(dir: 'libs', ...) line.
Runtime requirements
Drop the built jar into your modpack alongside:
| Mod | Version |
|---|---|
| NeoForge | 21.1.x (1.21.1) |
| Gravestone (henkelmax) | 1.21.1-1.0.19 or later |
| Sable | 1.0+ |
| Sable Companion | 1.6+ (bundled inside this jar via JarInJar; no separate install needed) |
| Create Aeronautics | any version that uses Sable |
The mixin only attaches to de.maxhenkel.gravestone.events.DeathEvents.playerDeath's
single call to GraveUtils.getGraveStoneLocation(Level, BlockPos). The signature
of that call has been stable across gravestone 1.21.1-1.0.19 → 1.0.37, so the
mod should work with any of them. If a future build refactors that method, the
mixin will fail loudly at load time (defaultRequire: 1) rather than silently
no-op.
File layout
gravestone-sable-compat/
├─ build.gradle
├─ gradle.properties
├─ settings.gradle
├─ src/main/java/com/example/gravestonesablecompat/
│ ├─ GravestoneSableCompat.java # tiny @Mod entry point
│ └─ mixin/DeathEventsMixin.java # the actual fix (one @WrapOperation)
└─ src/main/resources/
├─ META-INF/neoforge.mods.toml
├─ gravestone_sable_compat.mixins.json
└─ pack.mcmeta
License
MIT — go wild.