quaver-rs 0.1.0

A Rust library for parsing and analyzing Quaver rhythm game maps
Documentation
use bitflags::bitflags;

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct ModIdentifier: u64 {
        const NONE = 1 << 63; // -1L in C# becomes 1 << 63
        const NO_SLIDER_VELOCITY = 1 << 0; // No Slider Velocity
        const SPEED_05X = 1 << 1; // Speed 0.5x
        const SPEED_06X = 1 << 2; // Speed 0.6x
        const SPEED_07X = 1 << 3; // Speed 0.7x
        const SPEED_08X = 1 << 4; // Speed 0.8x
        const SPEED_09X = 1 << 5; // Speed 0.9x
        const SPEED_11X = 1 << 6; // Speed 1.1x
        const SPEED_12X = 1 << 7; // Speed 1.2x
        const SPEED_13X = 1 << 8; // Speed 1.3x
        const SPEED_14X = 1 << 9; // Speed 1.4x
        const SPEED_15X = 1 << 10; // Speed 1.5x
        const SPEED_16X = 1 << 11; // Speed 1.6x
        const SPEED_17X = 1 << 12; // Speed 1.7x
        const SPEED_18X = 1 << 13; // Speed 1.8x
        const SPEED_19X = 1 << 14; // Speed 1.9x
        const SPEED_20X = 1 << 15; // Speed 2.0x
        const STRICT = 1 << 16; // Makes the accuracy hit windows harder
        const CHILL = 1 << 17; // Makes the accuracy hit windows easier
        const NO_PAUSE = 1 << 18; // Disallows pausing
        const AUTOPLAY = 1 << 19; // The game automatically plays it
        const PAUSED = 1 << 20; // The user paused during gameplay
        const NO_FAIL = 1 << 21; // Unable to fail during gameplay
        const NO_LONG_NOTES = 1 << 22; // Converts LNs into regular notes
        const RANDOMIZE = 1 << 23; // Randomizes the playfield's lanes
        const SPEED_055X = 1 << 24; // Speed 0.55x
        const SPEED_065X = 1 << 25; // Speed 0.65x
        const SPEED_075X = 1 << 26; // Speed 0.75x
        const SPEED_085X = 1 << 27; // Speed 0.85x
        const SPEED_095X = 1 << 28; // Speed 0.95x
        const INVERSE = 1 << 29; // Converts regular notes into LNs and LNs into gaps
        const FULL_LN = 1 << 30; // Converts regular notes into LNs, keeps existing LNs
        const MIRROR = 1 << 31; // Flips the map horizontally
        const COOP = 1 << 32; // Allows multiple people to play together on one client
        const SPEED_105X = 1 << 33; // Speed 1.05x
        const SPEED_115X = 1 << 34; // Speed 1.15x
        const SPEED_125X = 1 << 35; // Speed 1.25x
        const SPEED_135X = 1 << 36; // Speed 1.35x
        const SPEED_145X = 1 << 37; // Speed 1.45x
        const SPEED_155X = 1 << 38; // Speed 1.55x
        const SPEED_165X = 1 << 39; // Speed 1.65x
        const SPEED_175X = 1 << 40; // Speed 1.75x
        const SPEED_185X = 1 << 41; // Speed 1.85x
        const SPEED_195X = 1 << 42; // Speed 1.95x
        const HEALTH_ADJUST = 1 << 43; // Test mod for making long note windows easier
        const NO_MISS = 1 << 44; // You miss, you die
    }
}

impl ModIdentifier {
    /// Get the audio rate from selected mods
    pub fn get_rate_from_mods(&self) -> f32 {
        if self.contains(ModIdentifier::NONE) {
            return 1.0;
        }

        if self.contains(ModIdentifier::SPEED_05X) { 0.5 }
        else if self.contains(ModIdentifier::SPEED_055X) { 0.55 }
        else if self.contains(ModIdentifier::SPEED_06X) { 0.6 }
        else if self.contains(ModIdentifier::SPEED_065X) { 0.65 }
        else if self.contains(ModIdentifier::SPEED_07X) { 0.7 }
        else if self.contains(ModIdentifier::SPEED_075X) { 0.75 }
        else if self.contains(ModIdentifier::SPEED_08X) { 0.8 }
        else if self.contains(ModIdentifier::SPEED_085X) { 0.85 }
        else if self.contains(ModIdentifier::SPEED_09X) { 0.9 }
        else if self.contains(ModIdentifier::SPEED_095X) { 0.95 }
        else if self.contains(ModIdentifier::SPEED_105X) { 1.05 }
        else if self.contains(ModIdentifier::SPEED_11X) { 1.1 }
        else if self.contains(ModIdentifier::SPEED_115X) { 1.15 }
        else if self.contains(ModIdentifier::SPEED_12X) { 1.2 }
        else if self.contains(ModIdentifier::SPEED_125X) { 1.25 }
        else if self.contains(ModIdentifier::SPEED_13X) { 1.3 }
        else if self.contains(ModIdentifier::SPEED_135X) { 1.35 }
        else if self.contains(ModIdentifier::SPEED_14X) { 1.4 }
        else if self.contains(ModIdentifier::SPEED_145X) { 1.45 }
        else if self.contains(ModIdentifier::SPEED_15X) { 1.5 }
        else if self.contains(ModIdentifier::SPEED_155X) { 1.55 }
        else if self.contains(ModIdentifier::SPEED_16X) { 1.6 }
        else if self.contains(ModIdentifier::SPEED_165X) { 1.65 }
        else if self.contains(ModIdentifier::SPEED_17X) { 1.7 }
        else if self.contains(ModIdentifier::SPEED_175X) { 1.75 }
        else if self.contains(ModIdentifier::SPEED_18X) { 1.8 }
        else if self.contains(ModIdentifier::SPEED_185X) { 1.85 }
        else if self.contains(ModIdentifier::SPEED_19X) { 1.9 }
        else if self.contains(ModIdentifier::SPEED_195X) { 1.95 }
        else if self.contains(ModIdentifier::SPEED_20X) { 2.0 }
        else { 1.0 }
    }

    /// Get mods from a given rate
    pub fn from_rate(rate: f32) -> ModIdentifier {
        match rate {
            0.5 => ModIdentifier::SPEED_05X,
            0.55 => ModIdentifier::SPEED_055X,
            0.6 => ModIdentifier::SPEED_06X,
            0.65 => ModIdentifier::SPEED_065X,
            0.7 => ModIdentifier::SPEED_07X,
            0.75 => ModIdentifier::SPEED_075X,
            0.8 => ModIdentifier::SPEED_08X,
            0.85 => ModIdentifier::SPEED_085X,
            0.9 => ModIdentifier::SPEED_09X,
            0.95 => ModIdentifier::SPEED_095X,
            1.05 => ModIdentifier::SPEED_105X,
            1.1 => ModIdentifier::SPEED_11X,
            1.15 => ModIdentifier::SPEED_115X,
            1.2 => ModIdentifier::SPEED_12X,
            1.25 => ModIdentifier::SPEED_125X,
            1.3 => ModIdentifier::SPEED_13X,
            1.35 => ModIdentifier::SPEED_135X,
            1.4 => ModIdentifier::SPEED_14X,
            1.45 => ModIdentifier::SPEED_145X,
            1.5 => ModIdentifier::SPEED_15X,
            1.55 => ModIdentifier::SPEED_155X,
            1.6 => ModIdentifier::SPEED_16X,
            1.65 => ModIdentifier::SPEED_165X,
            1.7 => ModIdentifier::SPEED_17X,
            1.75 => ModIdentifier::SPEED_175X,
            1.8 => ModIdentifier::SPEED_18X,
            1.85 => ModIdentifier::SPEED_185X,
            1.9 => ModIdentifier::SPEED_19X,
            1.95 => ModIdentifier::SPEED_195X,
            2.0 => ModIdentifier::SPEED_20X,
            _ => ModIdentifier::NONE,
        }
    }

    /// Get mods string representation
    pub fn to_string(&self) -> String {
        if self.is_empty() || self.contains(ModIdentifier::NONE) {
            return "None".to_string();
        }

        let mut mod_strings = Vec::new();

        // Speed mods (insert at beginning)
        if self.contains(ModIdentifier::SPEED_05X) { mod_strings.insert(0, "0.5x".to_string()); }
        if self.contains(ModIdentifier::SPEED_055X) { mod_strings.insert(0, "0.55x".to_string()); }
        if self.contains(ModIdentifier::SPEED_06X) { mod_strings.insert(0, "0.6x".to_string()); }
        if self.contains(ModIdentifier::SPEED_065X) { mod_strings.insert(0, "0.65x".to_string()); }
        if self.contains(ModIdentifier::SPEED_07X) { mod_strings.insert(0, "0.7x".to_string()); }
        if self.contains(ModIdentifier::SPEED_075X) { mod_strings.insert(0, "0.75x".to_string()); }
        if self.contains(ModIdentifier::SPEED_08X) { mod_strings.insert(0, "0.8x".to_string()); }
        if self.contains(ModIdentifier::SPEED_085X) { mod_strings.insert(0, "0.85x".to_string()); }
        if self.contains(ModIdentifier::SPEED_09X) { mod_strings.insert(0, "0.9x".to_string()); }
        if self.contains(ModIdentifier::SPEED_095X) { mod_strings.insert(0, "0.95x".to_string()); }
        if self.contains(ModIdentifier::SPEED_105X) { mod_strings.insert(0, "1.05x".to_string()); }
        if self.contains(ModIdentifier::SPEED_11X) { mod_strings.insert(0, "1.1x".to_string()); }
        if self.contains(ModIdentifier::SPEED_115X) { mod_strings.insert(0, "1.15x".to_string()); }
        if self.contains(ModIdentifier::SPEED_12X) { mod_strings.insert(0, "1.2x".to_string()); }
        if self.contains(ModIdentifier::SPEED_125X) { mod_strings.insert(0, "1.25x".to_string()); }
        if self.contains(ModIdentifier::SPEED_13X) { mod_strings.insert(0, "1.3x".to_string()); }
        if self.contains(ModIdentifier::SPEED_135X) { mod_strings.insert(0, "1.35x".to_string()); }
        if self.contains(ModIdentifier::SPEED_14X) { mod_strings.insert(0, "1.4x".to_string()); }
        if self.contains(ModIdentifier::SPEED_145X) { mod_strings.insert(0, "1.45x".to_string()); }
        if self.contains(ModIdentifier::SPEED_15X) { mod_strings.insert(0, "1.5x".to_string()); }
        if self.contains(ModIdentifier::SPEED_155X) { mod_strings.insert(0, "1.55x".to_string()); }
        if self.contains(ModIdentifier::SPEED_16X) { mod_strings.insert(0, "1.6x".to_string()); }
        if self.contains(ModIdentifier::SPEED_165X) { mod_strings.insert(0, "1.65x".to_string()); }
        if self.contains(ModIdentifier::SPEED_17X) { mod_strings.insert(0, "1.7x".to_string()); }
        if self.contains(ModIdentifier::SPEED_175X) { mod_strings.insert(0, "1.75x".to_string()); }
        if self.contains(ModIdentifier::SPEED_18X) { mod_strings.insert(0, "1.8x".to_string()); }
        if self.contains(ModIdentifier::SPEED_185X) { mod_strings.insert(0, "1.85x".to_string()); }
        if self.contains(ModIdentifier::SPEED_19X) { mod_strings.insert(0, "1.9x".to_string()); }
        if self.contains(ModIdentifier::SPEED_195X) { mod_strings.insert(0, "1.95x".to_string()); }
        if self.contains(ModIdentifier::SPEED_20X) { mod_strings.insert(0, "2.0x".to_string()); }

        // Other mods
        if self.contains(ModIdentifier::NO_SLIDER_VELOCITY) { mod_strings.push("NSV".to_string()); }
        if self.contains(ModIdentifier::STRICT) { mod_strings.push("ST".to_string()); }
        if self.contains(ModIdentifier::CHILL) { mod_strings.push("CH".to_string()); }
        if self.contains(ModIdentifier::NO_PAUSE) { mod_strings.push("NP".to_string()); }
        if self.contains(ModIdentifier::AUTOPLAY) { mod_strings.push("AP".to_string()); }
        if self.contains(ModIdentifier::PAUSED) { mod_strings.push("PS".to_string()); }
        if self.contains(ModIdentifier::NO_FAIL) { mod_strings.push("NF".to_string()); }
        if self.contains(ModIdentifier::NO_LONG_NOTES) { mod_strings.push("NLN".to_string()); }
        if self.contains(ModIdentifier::RANDOMIZE) { mod_strings.push("RND".to_string()); }
        if self.contains(ModIdentifier::INVERSE) { mod_strings.push("INV".to_string()); }
        if self.contains(ModIdentifier::FULL_LN) { mod_strings.push("FLN".to_string()); }
        if self.contains(ModIdentifier::MIRROR) { mod_strings.push("MR".to_string()); }
        if self.contains(ModIdentifier::COOP) { mod_strings.push("Co-op".to_string()); }
        if self.contains(ModIdentifier::HEALTH_ADJUST) { mod_strings.push("HPA".to_string()); }
        if self.contains(ModIdentifier::NO_MISS) { mod_strings.push("NM".to_string()); }

        mod_strings.join(", ")
    }
}