# Ambient Audio Zone A Paper 26.2 plugin for immersive, directional ambient audio driven by WorldEdit cuboid selections. Zones use any vanilla or resource-pack sound event (`minecraft:...` or `namespace:...`), are stored in YAML, and are indexed by chunk rather than scanned globally. ## Requirements - **Paper 26.2** (`26.2.build.92-stable` API target) and **Java 25** - **WorldEdit 7.4.4+** installed on the server (for selection-backed create/region editing) - A resource pack installed on clients when using custom sound IDs Drop `AmbientAudioZone.jar` into `plugins/` and restart. It creates `plugins/AmbientAudioZone/config.yml` and `zones.yml`. ## Commands | Command | Description | Permission | | --- | --- | --- | | `/ambientaudio create ` | Creates a zone from your complete WorldEdit selection. Origin starts at your current location. | `ambientaudio.create` | | `/ambientaudio edit region` | Replaces the zone cuboid with your WorldEdit selection. | `ambientaudio.edit` | | `/ambientaudio edit origin [here\|x y z]` | Sets the directional sound source. | `ambientaudio.edit` | | `/ambientaudio edit sound ` | Changes the sound event ID. | `ambientaudio.edit` | | `/ambientaudio edit fade ` | Sets the selection activation/fade envelope. | `ambientaudio.edit` | | `/ambientaudio edit volume\|pitch ` | Sets the sound gain or pitch. | `ambientaudio.edit` | | `/ambientaudio edit category ` | Sets a Bukkit `SoundCategory`, e.g. `MUSIC`, `RECORDS`, `AMBIENT`, `MASTER`. | `ambientaudio.edit` | | `/ambientaudio edit loop\|enabled ` | Changes loop metadata or enable state. | `ambientaudio.edit` | | `/ambientaudio edit priority ` | Sets overlap priority. | `ambientaudio.edit` | | `/ambientaudio delete ` | Deletes a zone. | `ambientaudio.delete` | | `/ambientaudio list` | Lists zones. | `ambientaudio.list` | | `/ambientaudio reload` | Reloads both YAML files and rebuilds the index. | `ambientaudio.reload` | `ambientaudio.admin` grants all administrative commands (default: OP). The `/aaz` alias is available. ## Zone configuration ```yaml zones: nightclub: world: world sound: lexian:music/nightclub origin: x: 120 y: 65 z: -45 region: min: { x: 100, y: 60, z: -60 } max: { x: 140, y: 80, z: -20 } fade-distance: 32 volume: 1.0 pitch: 1.0 category: RECORDS loop: true priority: 100 enabled: true ``` `fade-distance` expands the cuboid's audible envelope. With `playback.follow-player: true` (the default), the sound is attached to each listener and its volume fades from the configured volume inside the cuboid to silence at the edge of the fade envelope. Set it to `false` to use the fixed `origin` as a directional source instead. ## Overlaps and performance By default, only the audible zone with the highest `priority` is selected. Set `playback.blend-overlapping-zones: true` in `config.yml` to play every audible zone. The zone index assigns a zone only to chunks touched by its fade-expanded X/Z bounds; each playback pass then evaluates only the list for a player's current chunk. The interval and grace period are configurable: ```yaml playback: check-interval-ticks: 10 leave-grace-ticks: 100 blend-overlapping-zones: false follow-player: true loop-restart-ticks: 2680 ``` When a selected zone remains selected, Ambient Audio Zone normally sends no new sound packet. In follow-player mode it re-emits only when the calculated fade changes materially, and it uses an entity-attached packet so the sound follows the player. Leaving starts a configurable grace timer; returning before it expires preserves the existing client playback instead of restarting it. `loop-restart-ticks` is a fallback for sounds whose resource-pack definition does not loop; set it to the exact sound length, while resource-pack `loop: true` remains the seamless option. Reloading or editing a zone intentionally replaces its active sound. ## Resource-pack looping note Minecraft's public sound packet has no server-controlled *playback position*, pause, or true loop flag. For seamless loops, define custom events in the resource pack and let the **client** loop/stream them, for example: ```json { "music/nightclub": { "sounds": [{ "name": "lexian:music/nightclub", "stream": true, "loop": true }] } } ``` Use that event as `lexian:music/nightclub` in the zone. The plugin deliberately does not repeatedly replay a selected sound—doing so would cause audible starts and destroy seamless loops. Vanilla one-shot events play normally; their exact loop behaviour is determined by the vanilla sound definition. ## Build ```bash mvn verify ``` The GitHub Actions workflow builds with Java 25 on pushes and pull requests.