LOADING FINALLY WORKS!

main
aprzn 2 years ago
parent 821318a5ad
commit cb756f39d0

@ -20,8 +20,8 @@ pub enum Song {
Unknown, Unknown,
} }
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct SongResponse([Option<String>; 9]); pub struct SongResponse([Option<String>; 10]);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Level { pub struct Level {
@ -35,9 +35,9 @@ pub struct InnerLevel(String);
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct RawLinesTriplet { pub struct RawLinesTriplet {
orange: Lines<Duration>, // 0.8 pub orange: Lines<Duration>, // 0.8
yellow: Lines<Duration>, // 0.9 pub yellow: Lines<Duration>, // 0.9
green: Lines<Duration>, // 1.0 pub green: Lines<Duration>, // 1.0
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -103,13 +103,16 @@ impl Song {
match self { match self {
Self::Newgrounds { id } => { Self::Newgrounds { id } => {
let mut out = SongResponse(Default::default()); let mut out = SongResponse(Default::default());
req::Client::new() dbg!(req::ClientBuilder::new()
.post("http://boomlings.com/database/getGJSongInfo.php") .user_agent("")
.body(format!( .build()?
r#" {{ "secret": "Wmfd2893gb7", "songID": {id} }} "#, .post("http://www.boomlings.com/database/getGJSongInfo.php")
)) // .body(dbg!(format!(
// r#" {{ "secret": "Wmfd2893gb7", "songID": {} }} "#, id
// )))
.form(&[("songID", id.to_string().as_ref()), ("secret", "Wmfd2893gb7")])
.send()? .send()?
.text()? .text()?)
.split("~|~") .split("~|~")
.array_chunks() .array_chunks()
.try_for_each(|[id, value]| -> Result<(), SongRequestError> { .try_for_each(|[id, value]| -> Result<(), SongRequestError> {

@ -24,8 +24,7 @@ struct PipeDash {
selected_level: Option<usize>, selected_level: Option<usize>,
level_list: Vec<gd::Level>, level_list: Vec<gd::Level>,
loaded_level_checksum: Option<(gd::Level, md5::Digest)>, loaded_level_checksum: Option<(gd::Level, md5::Digest)>,
loaded_song: Option<Song>, editor_mode: EditorMode,
editor: Editor,
errors: VecDeque<Box<dyn Error>>, errors: VecDeque<Box<dyn Error>>,
} }
@ -49,6 +48,7 @@ enum EditorMode {
Full {editor: Editor, song: Song} Full {editor: Editor, song: Song}
} }
#[derive(Default)]
struct Editor { struct Editor {
state: EditorState, state: EditorState,
data: GdlData, data: GdlData,
@ -105,15 +105,17 @@ enum SongError {
struct BeatRateWidget<'a> { struct BeatRateWidget<'a> {
state: &'a mut EditorState, state: &'a mut EditorState,
beat_rate: &'a mut music::BeatRate, beat_rate: Option<&'a mut music::BeatRate>,
} }
struct TimeSignatureWidget<'a> { struct TimeSignatureWidget<'a> {
state: &'a mut EditorState, state: &'a mut EditorState,
time_signatures: &'a mut music::TimeSignature, time_signatures: Option<&'a mut music::TimeSignature>,
} }
struct LinesWidget<'a> { struct LinesWidget<'a, T = music::BeatPosition>
where T: Ord
{
state: &'a mut EditorState, state: &'a mut EditorState,
lines: &'a mut music::Lines, lines: &'a mut music::Lines<T>,
color: Color, color: Color,
} }
struct WaveformWidget<'a> { struct WaveformWidget<'a> {
@ -137,18 +139,54 @@ impl From<Color> for eframe::epaint::Color32 {
} }
} }
impl EditorMode {
pub fn display(&mut self, ui: &mut egui::Ui) {
match self {
EditorMode::RhythmWizard { editor, song } => {
},
EditorMode::Full { editor, song } => {
ui.add(editor.time_signature_widget());
ui.add(editor.beat_rate_widget());
ui.add(editor.lines_widget(Color::Green));
ui.add(editor.lines_widget(Color::Orange));
ui.add(editor.lines_widget(Color::Yellow));
ui.add(editor.waveform_widget(song));
},
EditorMode::NoSong => {},
}
}
}
impl Default for EditorState {
fn default() -> Self {
EditorState { scroll_pos: 0f32, pts_per_second: 10f32, subdivisions: 4f32 }
}
}
impl Default for GdlData {
fn default() -> Self {
GdlData {
green_lines: Default::default(),
orange_lines: Default::default(),
yellow_lines: Default::default(),
beat_rate: music::StaticBeatRate::from_bpm(120f32).into(),
time_signatures: music::StaticTimeSignature::new(4, 4).into(),
}
}
}
impl Song { impl Song {
pub fn try_new(gd_song: &gd::Song) -> Result<Self, SongError> { pub fn try_new(gd_song: &gd::Song) -> Result<Self, SongError> {
if let &gd::Song::Newgrounds { id } = gd_song { if let &gd::Song::Newgrounds { id } = gd_song {
let song_response = gd_song.get_response(); let song_result = gd_song.get_response();
let song_path = gd::save_path().join(format!("{id}.mp3")); let song_path = gd::save_path().join(format!("{id}.mp3"));
let (file, name) = match (File::open(&song_path), song_response) { let (file, name) = match (File::open(&song_path), song_result) {
(Ok(file), response) => { (Ok(file), response) => {
let name = response let name = response
.ok() .ok()
.and_then(|response| response.name().map(Into::into)) .and_then(|response| response.name().map(Into::into))
.unwrap_or_default(); .unwrap_or("Missing Name".into());
(file, name) (file, name)
} }
@ -179,14 +217,14 @@ impl Editor {
pub fn beat_rate_widget(&mut self) -> BeatRateWidget { pub fn beat_rate_widget(&mut self) -> BeatRateWidget {
BeatRateWidget { BeatRateWidget {
state: &mut self.state, state: &mut self.state,
beat_rate: &mut self.data.beat_rate, beat_rate: Some(&mut self.data.beat_rate),
} }
} }
pub fn time_signature_widget(&mut self) -> TimeSignatureWidget { pub fn time_signature_widget(&mut self) -> TimeSignatureWidget {
TimeSignatureWidget { TimeSignatureWidget {
state: &mut self.state, state: &mut self.state,
time_signatures: &mut self.data.time_signatures, time_signatures: Some(&mut self.data.time_signatures),
} }
} }
@ -210,6 +248,59 @@ impl Editor {
} }
} }
impl WizardEditor {
pub fn beat_rate_widget(&mut self) -> BeatRateWidget {
BeatRateWidget {
state: &mut self.state,
beat_rate: self.data.beat_rate.as_mut(),
}
}
pub fn time_signature_widget(&mut self) -> TimeSignatureWidget {
TimeSignatureWidget {
state: &mut self.state,
time_signatures: self.data.time_signatures.as_mut(),
}
}
pub fn lines_widget(&mut self, col: Color) -> LinesWidget<chrono::Duration> {
LinesWidget {
state: &mut self.state,
lines: match col {
Color::Green => &mut self.data.green_lines,
Color::Yellow => &mut self.data.yellow_lines,
Color::Orange => &mut self.data.orange_lines,
},
color: col,
}
}
pub fn waveform_widget<'a>(&'a mut self, song: &'a Song) -> WaveformWidget {
WaveformWidget {
state: &mut self.state,
song,
}
}
}
impl From<gd::RawLinesTriplet> for WizardData {
fn from(lines: gd::RawLinesTriplet) -> Self {
Self {
green_lines: lines.green,
orange_lines: lines.orange,
yellow_lines: lines.yellow,
beat_rate: None,
time_signatures: None,
}
}
}
impl From<gd::RawLinesTriplet> for WizardEditor {
fn from(lines: gd::RawLinesTriplet) -> Self {
Self { state: Default::default(), data: lines.into() }
}
}
impl<'a> egui::Widget for BeatRateWidget<'a> { impl<'a> egui::Widget for BeatRateWidget<'a> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response { fn ui(self, ui: &mut egui::Ui) -> egui::Response {
let (rect, res) = allocate_editor_space(ui); let (rect, res) = allocate_editor_space(ui);
@ -280,23 +371,9 @@ impl PipeDash {
selected_level: None, selected_level: None,
msg_queue: VecDeque::new(), msg_queue: VecDeque::new(),
level_list: gd::Level::load_all(), level_list: gd::Level::load_all(),
loaded_song: None,
loaded_level_checksum: None, loaded_level_checksum: None,
errors: VecDeque::new(), errors: VecDeque::new(),
editor: Editor { editor_mode: EditorMode::NoSong,
state: EditorState {
scroll_pos: 0f32,
pts_per_second: 5f32,
subdivisions: 4.0,
},
data: GdlData {
beat_rate: music::StaticBeatRate::from_bpm(120f32).into(),
time_signatures: music::StaticTimeSignature::new(4, 4).into(),
green_lines: music::Lines::new(),
orange_lines: music::Lines::new(),
yellow_lines: music::Lines::new(),
},
},
} }
} }
@ -336,29 +413,23 @@ impl PipeDash {
fn center_panel(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { fn center_panel(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.vertical_centered_justified(|ui| { ui.vertical_centered_justified(|ui| {
use EditorMode::*;
ui.label( ui.label(
egui::RichText::new(match &self.loaded_song { egui::RichText::new(match &self.editor_mode {
Some(song) => &song.name, RhythmWizard { song, .. } | Full { song, .. } => &song.name,
None => "No song loaded...", NoSong => "No song loaded...",
}) })
.size(32.0), .size(32.0),
); );
ui.label( ui.label(
egui::RichText::new(match &self.loaded_song { egui::RichText::new(match &self.editor_mode {
Some(song) => song.id.to_string(), RhythmWizard { song, .. } | Full { song, .. } => song.id.to_string(),
None => "No song loaded...".into(), NoSong => "No song loaded...".into(),
}) })
.size(20.0), .size(20.0),
); );
if let Some(song) = &self.loaded_song { self.editor_mode.display(ui);
ui.add(self.editor.time_signature_widget());
ui.add(self.editor.beat_rate_widget());
ui.add(self.editor.lines_widget(Color::Green));
ui.add(self.editor.lines_widget(Color::Orange));
ui.add(self.editor.lines_widget(Color::Yellow));
ui.add(self.editor.waveform_widget(song));
}
}); });
}); });
} }
@ -369,32 +440,36 @@ impl PipeDash {
Message::CloseError => { self.errors.pop_front(); }, Message::CloseError => { self.errors.pop_front(); },
Message::LoadLevel => { Message::LoadLevel => {
// Load song, GdlData, checksum; if there are no lines go straight into editor, otherwise // Load song, GdlData, checksum; if there are no lines go straight into editor, otherwise
// do some sort of rhythm wizard thing // start the rhythm wizard
// [X] Load song
// [ ] Load GdlData
// [X] Load checksum
// [ ] Handle rhythm wizard
let level = self let level = self
.selected_level .selected_level
.and_then(|idx| self.level_list.get(idx)) .and_then(|idx| self.level_list.get(idx))
.unwrap() // will not panic. selected_level range is same as level_list... .unwrap() // will not panic. selected_level range is same as level_list...
.clone(); // ...length - 1; message will not be sent if selected_level is none .clone(); // ...length - 1; message will not be sent if selected_level is none
match Song::try_new(&level.song()) { let song = match Song::try_new(&level.song()) {
Ok(song) => { Ok(song) => song,
self.loaded_song = Some(song);
},
Err(e) => { Err(e) => {
self.errors.push_front(Box::new(e)); self.errors.push_front(Box::new(e));
return; return;
}, },
} };
let inner_level = level.load_inner(); let inner_level = level.load_inner();
let lines = inner_level.get_lines(); let lines = inner_level.get_lines();
if lines.orange.empty() && lines.green.empty() && lines.yellow.empty() {
self.editor_mode = EditorMode::Full {
editor: Default::default(),
song,
}
} else {
self.editor_mode = EditorMode::RhythmWizard {
editor: lines.into(),
song,
}
}
self.loaded_level_checksum = Some((level, inner_level.hash())); self.loaded_level_checksum = Some((level, inner_level.hash()));
todo!();
} }
} }
} }
@ -428,6 +503,7 @@ impl eframe::App for PipeDash {
} }
fn main() { fn main() {
std::fs::create_dir_all(project_dirs().data_local_dir());
simplelog::WriteLogger::init( simplelog::WriteLogger::init(
simplelog::LevelFilter::Info, simplelog::LevelFilter::Info,
simplelog::Config::default(), simplelog::Config::default(),

Loading…
Cancel
Save