rgchart 0.0.13

A library for parsing and writing rhythm game charts.
Documentation
use crate::models::common::*;
use crate::models::fluxis::{self, FscFile, Colors};
use crate::models::generic::{ GenericManiaChart, HitSoundType};

fn get_hitsound_type(hitsound_type: HitSoundType) -> String {
    match hitsound_type {
        HitSoundType::Normal => ":normal".to_string(),
        HitSoundType::Clap => ":clap".to_string(),
        HitSoundType::Whistle => ":whistle".to_string(),
        HitSoundType::Finish => ":finish".to_string(),
    }
}

pub(crate) fn to_fsc_generic(
    chart: &GenericManiaChart,
) -> Result<String, Box<dyn std::error::Error>> {
    let metadata = fluxis::Metadata {
        title: chart.metadata.title.clone(),
        title_rm: Some(chart.metadata.alt_title.clone()),
        artist: chart.metadata.artist.clone(),
        artist_rm: Some(chart.metadata.alt_artist.clone()),
        mapper: chart.metadata.creator.clone(),
        difficulty: chart.chartinfo.difficulty_name.clone(),
        source: Some(chart.metadata.source.clone()),
        tags: chart.metadata.tags.join(" "),
        previewtime: chart.chartinfo.preview_time as i32,
        ..Default::default()
    };

    let timing_points = chart
        .timing_points
        .bpm_changes()
        .map(|tp| fluxis::TimingPoint {
            time: tp.time as f32,
            bpm: tp.change.value,
            ..Default::default()
        })
        .collect();

    let scroll_velocities = chart
        .timing_points
        .sv_changes()
        .map(|sv| fluxis::ScrollVelocity {
            time: sv.time as f32,
            multiplier: sv.change.value,
            ..Default::default()
        })
        .collect();

    let mut fsc_hitobjects = Vec::new();

    for hitobject in chart.hitobjects.iter() {
        let time = hitobject.time as f32;
        let lane = hitobject.lane as isize;

        match hitobject.key.key_type {
            KeyType::Normal => {
                fsc_hitobjects.push(fluxis::HitObject {
                    time,
                    lane,
                    hitsound: get_hitsound_type(HitSoundType::Normal),
                    ..Default::default()
                });
            }
            KeyType::SliderStart => {
                let slider_end_time = if let Some(time) = hitobject.key.slider_end_time() {
                    time
                } else {
                    0
                };

                fsc_hitobjects.push(fluxis::HitObject {
                    time,
                    lane,
                    holdtime: (slider_end_time - hitobject.time) as f32,
                    hitsound: get_hitsound_type(hitobject.keysound.hitsound_type),
                    ..Default::default()
                });
            }
            _ => continue,
        }
    }

    let fsc_chart = FscFile {
        audio_file: chart.chartinfo.song_path.clone(),
        background_file: chart.chartinfo.bg_path.clone(),
        video_file: chart.chartinfo.video_path.clone(),
        metadata,
        colors: Colors::default(),
        hit_objects: fsc_hitobjects,
        timing_points,
        scroll_velocities,
        accuracy_difficulty: Some(chart.chartinfo.od),
        health_difficulty: Some(chart.chartinfo.hp),
        ..Default::default()
    };

    let json_string = FscFile::to_str(&fsc_chart)?;
    Ok(json_string)
}