Skip to main content

yog_formats/
sound.rs

1//! `.ysound` — a sound event: what the game plays when it's played. The
2//! sounds themselves are `.yres` sounds (`sound: @Sounds.abacus1`) as given
3//! — any format, normalised by the build; this says which of them play,
4//! how loud and how high, and the subtitle shown. Its id is its path under
5//! `resources/sound/` with `/` as `.` (`resources/sound/casting/cast.ysound`
6//! is `<mod id>:casting.cast`), named elsewhere as `@sound:<id>`. Yog Data,
7//! like every source format; the build writes the game's `sounds.json`.
8
9use yog_data::{Res, Schema};
10
11/// Where `.ysound` files live, under `resources/`.
12pub const DIR: &str = yog_ids::kind::SOUND;
13
14/// A `.ysound`.
15#[derive(Schema, Debug, Clone, PartialEq)]
16pub struct SoundFile {
17    /// What plays: one of them, picked by weight.
18    pub sounds: Vec<Variant>,
19    /// The subtitle shown when it plays: a `.yres` text.
20    pub subtitle: Option<Res>,
21    /// Replaces the game's own sounds of the same event (another mod's, a resource pack's).
22    #[data(default)]
23    pub replace: bool,
24}
25
26/// One sound an event may play.
27#[derive(Schema, Debug, Clone, PartialEq)]
28pub struct Variant {
29    /// The sound: a `.yres` sound.
30    pub sound: Res,
31    /// 1 if not given.
32    pub volume: Option<f32>,
33    /// 1 if not given.
34    pub pitch: Option<f32>,
35    /// How often it's picked against the others (1 if not given).
36    pub weight: Option<u32>,
37    /// Streamed, not loaded whole: long sounds (music, ambience).
38    #[data(default)]
39    pub stream: bool,
40    /// Loaded with the resources, not when first played.
41    #[data(default)]
42    pub preload: bool,
43    /// Blocks it carries (16 if not given).
44    pub attenuation_distance: Option<u32>,
45}
46
47/// An event's id from its file's path under `resources/` (`sound/casting/cast.ysound`)
48/// and the mod's id; none for a file outside `resources/sound/`.
49#[must_use]
50pub fn id_of(mod_id: &str, rel: &str) -> Option<String> {
51    let path = rel
52        .strip_suffix(yog_ids::Format::Sound.ext())?
53        .strip_suffix(yog_ids::sep::DOT)?
54        .strip_prefix(DIR)?
55        .strip_prefix(yog_ids::sep::PATH)?;
56    Some(yog_ids::join(mod_id, &path.replace(yog_ids::sep::PATH, yog_ids::sep::DOT)))
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn an_event_is_named_by_its_path_under_sound() {
65        assert_eq!(
66            id_of("hex", "sound/casting/cast.ysound").as_deref(),
67            Some("hex:casting.cast")
68        );
69        assert_eq!(id_of("hex", "sound/abacus.ysound").as_deref(), Some("hex:abacus"));
70        assert_eq!(id_of("hex", "block/abacus.ysound"), None);
71        assert_eq!(id_of("hex", "sound/abacus.ytexture"), None);
72    }
73}