diff --git a/rust/src/replay.rs b/rust/src/replay.rs index 934ae3c..687b7a9 100644 --- a/rust/src/replay.rs +++ b/rust/src/replay.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, fs, io::Cursor, thread}; +use std::{ + collections::HashMap, + fs, + io::Cursor, + sync::mpsc::{Receiver, channel}, + thread, +}; use flate2::{Compression, bufread::GzDecoder, write::GzEncoder}; use godot::{ @@ -484,6 +490,11 @@ impl ReplayPlayback { } } +pub enum ReplaySaveEvent { + Error(String), + Done, +} + #[derive(GodotClass)] #[class(base=Node, init)] pub struct ReplayRecorder { @@ -494,6 +505,8 @@ pub struct ReplayRecorder { recording: bool, + pub recv: Option>, + base: Base, } @@ -546,17 +559,42 @@ impl INode for ReplayRecorder { self.current_frame = self.record_frame(); } } + + fn process(&mut self, _: f64) { + if let Some(recv) = &self.recv { + if let Ok(data) = recv.recv() { + match data { + ReplaySaveEvent::Error(err) => self.signals().on_saved().emit(&err), + ReplaySaveEvent::Done => self.signals().on_saved().emit(&String::new()), + } + self.recv.take(); + } + } + } } +#[godot_api] impl ReplayRecorder { - pub fn save_to(&self, path: &GString) { + #[signal] + pub fn on_saved(error: GString); + + pub fn save_to(&mut self, path: &GString) { let path = path.to_string(); let replay = self.replay.clone(); + + let (send, recv) = channel(); + self.recv = Some(recv); + thread::spawn(move || { let mut bytes = Vec::new(); let encoder = GzEncoder::new(&mut bytes, Compression::default()); - ciborium::into_writer(&replay, encoder).ok(); - fs::write(path, bytes).ok(); + match ciborium::into_writer(&replay, encoder) { + Ok(_) => match fs::write(path, bytes) { + Ok(_) => send.send(ReplaySaveEvent::Done).ok(), + Err(e) => send.send(ReplaySaveEvent::Error(e.to_string())).ok(), + }, + Err(e) => send.send(ReplaySaveEvent::Error(e.to_string())).ok(), + } }); } diff --git a/rust/src/ui/game_finished_screen.rs b/rust/src/ui/game_finished_screen.rs index e886c31..7f9c520 100644 --- a/rust/src/ui/game_finished_screen.rs +++ b/rust/src/ui/game_finished_screen.rs @@ -1,5 +1,8 @@ use godot::{ - classes::{Button, FileDialog, HBoxContainer, IPanel, Label, Panel}, + classes::{ + AcceptDialog, Button, FileDialog, HBoxContainer, IPanel, Label, Panel, PopupPanel, + window::WindowInitialPosition, + }, prelude::*, }; @@ -21,6 +24,9 @@ pub struct GameFinishedScreen { #[export] save_file_dialog: Option>, + saving_replay_popup: Option>, + saving_replay_accept_dialog: Option>, + base: Base, } @@ -45,6 +51,15 @@ impl IPanel for GameFinishedScreen { .file_selected() .connect_other(self, Self::save_replay); } + + if let Some(game) = &mut Game::singleton() + && let Some(recorder) = &mut game.bind_mut().replay_recorder + { + recorder + .signals() + .on_saved() + .connect_other(self, Self::on_replay_saved); + } } } @@ -103,10 +118,44 @@ impl GameFinishedScreen { } pub fn save_replay(&mut self, path: GString) { - if let Some(game) = &Game::singleton() - && let Some(recorder) = &game.bind().replay_recorder + if let Some(game) = &mut Game::singleton() + && let Some(recorder) = &mut game.bind_mut().replay_recorder { - recorder.bind().save_to(&path); + let mut popup = PopupPanel::new_alloc(); + popup.set_initial_position(WindowInitialPosition::CENTER_MAIN_WINDOW_SCREEN); + popup.set_title("Saving replay"); + let mut label = Label::new_alloc(); + label.set_text("Saving replay"); + popup.add_child(&label); + self.base_mut().add_child(&popup); + + popup.show(); + + self.saving_replay_popup = Some(popup); + + recorder.bind_mut().save_to(&path); } } + + fn on_replay_saved(&mut self, err: GString) { + if let Some(popup) = self.saving_replay_popup.clone() { + self.base_mut().remove_child(&popup); + } + + let mut popup = AcceptDialog::new_alloc(); + popup.set_initial_position(WindowInitialPosition::CENTER_MAIN_WINDOW_SCREEN); + popup.set_title("Save Finished"); + let mut label = Label::new_alloc(); + let text: GString = if err.is_empty() { + "Replay Saved!".into() + } else { + (&format!("Error: {}", err)).into() + }; + label.set_text(&text); + popup.add_child(&label); + + popup.show(); + + self.base_mut().add_child(&popup); + } } diff --git a/rust/src/ui/replay_finished_screen.rs b/rust/src/ui/replay_finished_screen.rs index 75744b7..8a38464 100644 --- a/rust/src/ui/replay_finished_screen.rs +++ b/rust/src/ui/replay_finished_screen.rs @@ -85,12 +85,4 @@ impl ReplayFinishedScreen { } } } - - pub fn save_replay(&mut self, path: GString) { - if let Some(game) = &Game::singleton() - && let Some(recorder) = &game.bind().replay_recorder - { - recorder.bind().save_to(&path); - } - } }