Skip to content
Download

Sounds

A sound container is what the game plays for one event: a set of sounds and how it plays them. A mod names one by its GUID, a SoundContainerId, and plays it, changes it or adds its own.

Inside a frame of the interface, frame.play(id) plays a container as an interface sound. Only that client hears it, and it comes from no place in the world. The interface chapter lists it with the widgets.

load.change_sound(id, change) sets the values a SoundChange gives and keeps the rest. The client applies every mod’s changes in load order when it first reads the container. Nothing is written to the game’s files or a save. A server checks the values and does nothing more, since servers play no sound.

ValueBound
volume, volume_randomness0 to 4
pitch0.25 to 4
pitch_randomness0 to 4
min_distance, max_distance0 to 500 metres, the least not past the greatest
loopedtrue or false
priority0 to 65535
use enshwick::content::Guid;
use enshwick::sound::{SoundChange, SoundContainerId};
fn init(load: &mut enshwick::Load<'_>) -> Result<(), enshwick::Off> {
let bell = SoundContainerId::from_guid(Guid::named("you.bells:bell"));
load.change_sound(bell, SoundChange { volume: Some(0.2), ..SoundChange::default() })
}

A notifier’s NotifierResource names the container it plays in defaultSound. Other game data names one too, such as an ambient entry’s soundContainer. A mod changes which container plays by serving a changed resource value. Any container’s GUID fits there, a vanilla one or one from add_sound.

use enshwick::resources::{Registry, Value};
use enshwick::sound::SoundContainerId;
const NOTIFIER: &str = "keen::NotifierResource";
fn init(load: &mut enshwick::Load<'_>) -> Result<(), enshwick::Off> {
let bell = SoundContainerId::from_guid(enshwick::content::Guid::named("you.bells:bell"));
let registry = Registry::game()?;
let ty = registry.named(NOTIFIER).ok_or_else(|| enshwick::Off::new("no notifiers"))?;
let Some(key) = load.host().resource_keys(Some(ty))?.into_iter().next() else {
return Ok(());
};
load.serve(key, key, move |base| {
let mut notifier = registry.decode(NOTIFIER, base).ok()?;
*notifier.field_mut("defaultSound")? = Value::Guid(bell.guid());
registry.encode(NOTIFIER, &notifier, Some(base)).ok()
})
}

With the unstable feature, load.add_sound(NewSound::new(id!("horn"), "sounds/horn.wav")) adds that WAV file of the mod’s folder and a container that plays it. It returns the container. Its GUID is the content id’s, so other mods play it by you.horns:horn. A data pack lists its sounds in sounds.toml.

The client holds the sound as the game holds its own uncompressed sounds, streamed from memory. A server checks the file and holds nothing.

A WAV file
Samples16-bit PCM
Channelsmono or stereo
Rate48000 Hz, the rate of every sound the game plays
Sizeat most 16 MiB a file and 64 MiB a mod
Lengthwhat 16 MiB holds: about 87 seconds of stereo, 174 of mono

A mod with sounds runs on both sides (side = "both"), so a client without it cannot join. A file past a bound, of another format or outside the mod’s folder refuses the call. Wrapped in load.feature("horn", ...), it turns off that sound alone. The reason shows in the log and on the Mods screen.

A sound that misleads players in a fight, such as an attack that does not happen, does not belong in a mod.