100 lines
4.0 KiB
Markdown
100 lines
4.0 KiB
Markdown
# 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.):
|
||
|
||
```bash
|
||
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](https://github.com/neoforged/MDK)).
|
||
|
||
Then build the mod:
|
||
|
||
```bash
|
||
./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)](https://modrinth.com/mod/gravestone-mod) | 1.21.1-1.0.19 or later |
|
||
| [Sable](https://modrinth.com/mod/sable) | 1.0+ |
|
||
| [Sable Companion](https://github.com/ryanhcode/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.
|