# AeronauticsCompat 1.0.6
A compatibility-patch mod for [Create: Aeronautics](https://github.com/Creators-of-Aeronautics/Simulated-Project) / [Sable](https://github.com/ryanhcode/sable) sub-levels (NeoForge 1.21.1).
Tested against Sable 1.0.6 and 1.1.1, Create: Aeronautics 1.0.3 and 1.1.3. All patches target stable behavior that has not changed between these versions.
All patches are **soft dependencies** — each one applies only when its target mod is installed. Uninstalling any of the target mods is safe; AeronauticsCompat stays loaded and continues to patch whatever else is present.
## Patches
### Etched × Sable: music discs on contraptions stop correctly
**Problem.** On a moving Sable contraption (e.g., Create: Aeronautics ship), music discs never stop playing after the disc is ejected. Affects **every** disc — vanilla, datapack, and Etched discs — as long as Etched is installed.
**Cause.** Etched's `LevelRendererMixin.modifySoundInstance` wraps every jukebox sound in `StopListeningSound`, which doesn't extend `AbstractSoundInstance`, so Sable's `AbstractSoundInstanceMixin` (which implements `SoundInstanceDelegated`) doesn't apply. On stop, Sable can't unwrap the sound to the `MovingSoundInstanceDelegate` keyed in OpenAL; the stop lookup misses and the sound plays forever.
**Fix.** Mixin `StopListeningSound implements SoundInstanceDelegated`, holding a `MovingSoundInstanceDelegate` back-reference. Sable's constructor now stores the wrapper on us at play-time and reads it back at stop-time. OpenAL's channel key matches on both ends.
*Activates when: Etched + Sable are both installed.*
### WaterFrames × Sable: TV audio on contraptions is audible
**Problem.** On a moving Sable contraption, WaterFrames TVs/projectors are silent, even at point-blank range. Video plays fine.
**Cause.** WaterFrames attenuates audio by the Euclidean distance from the block to the player. On a Sable contraption, the block's logical position is in a sub-level at coordinates millions of blocks from the player's world-space position, so the computed distance is astronomical and the volume is clamped to zero.
**Fix.** Mixin `@Inject` at HEAD of `WaterFrames.getDistance(Level, BlockPos, Position)`; when Sable is present, short-circuit to `Math.sqrt(SableCompanion.distanceSquaredWithSubLevels(level, Vec3.atCenterOf(pos), playerPos))`. This mirrors WaterFrames' existing Valkyrien Skies compat path exactly.
*Activates when: WaterFrames + Sable are both installed.*
### Citadel × Sable: mob pathfinding no longer crashes the server
**Problem.** Server OOMs (`java.lang.OutOfMemoryError: Java heap space`) whenever a Citadel-powered mob ticks near a Sable contraption. Affects everything that depends on Citadel — Alex's Mobs, Alex's Caves, L\_Ender's Cataclysm, etc. Vanilla mobs and other mod mobs are unaffected.
**Cause.** Sable's `SubLevelInclusiveLevelEntityGetter` wraps `Level#getEntities`, causing entity queries to also enumerate entities inside sub-levels. Those entities carry raw coordinates in sub-level space — tens of millions of blocks from the querying mob's position. When a Citadel mob picks such an entity as a target (or draws a stroll pos near one), its goal calls `AdvancedPathNavigate#moveToXYZ` with those coordinates. Citadel's `AbstractPathJob` sizes a `ChunkCache`'s `LevelChunk[][]` by the start-to-end bounding box; with end coords in the millions, the array allocation exhausts JVM heap instantly.
**Fix.** Mixin `AdvancedPathNavigate.moveToXYZ` at HEAD. If the horizontal span between the mob's actual position and the target exceeds 4096 blocks on either axis, return `null` — this looks to the goal exactly like "no path found, try again next tick." No path job is constructed, no `ChunkCache` allocated, no OOM. The check is symmetric, so legitimate in-world pathing AND legitimate mob-to-mob pathing between two entities on the same contraption (where both endpoints are in the same sub-level coordinate frame, and therefore close in relative terms) both pass through untouched.
*Activates when: Citadel + Sable are both installed.*
## Dependencies
- **Required**: NeoForge 1.21.1
- **Optional** (each enables one or more patches): Sable, Etched, WaterFrames, Citadel
No target mod is a hard dependency. The mod loads and logs which patches are active on startup.
## Building
```
./gradlew build
```
No external jars required in `libs/`. Compile-time stubs for Sable and WaterFrames live in `src/stubs/java/` and are excluded from the output jar.
## License
GPLv3.