Put loading replays on another thread, timeout recv
This commit is contained in:
parent
0cddfe93bb
commit
f6deb4b355
@ -4,6 +4,7 @@ use std::{
|
||||
io::Cursor,
|
||||
sync::mpsc::{Receiver, channel},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use flate2::{Compression, bufread::GzDecoder, write::GzEncoder};
|
||||
@ -24,11 +25,17 @@ use crate::{
|
||||
DamageSource, IPlayer, NetTransform, ball::Ball, buffs::Buffs, remote_player::RemotePlayer,
|
||||
telegrenade::Telegrenade, weapon::WeaponType,
|
||||
},
|
||||
popup_queue::{Popup, PopupQueue},
|
||||
ui::{hud::Hud, replay_hud::ReplayHud},
|
||||
};
|
||||
|
||||
pub const STANDALONE_REPLAY_GLOBAL: &str = "StandaloneReplayGlobal";
|
||||
|
||||
pub enum ReplayReadEvent {
|
||||
Done(Replay),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node, init)]
|
||||
pub struct StandaloneReplayManager {
|
||||
@ -50,6 +57,8 @@ pub struct StandaloneReplayManager {
|
||||
replay_hud: Option<Gd<ReplayHud>>,
|
||||
since_last_update: f64,
|
||||
|
||||
recv: Option<Receiver<ReplayReadEvent>>,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
@ -65,6 +74,37 @@ impl INode for StandaloneReplayManager {
|
||||
hud.bind_mut()
|
||||
.update_times(playback.bind().current_time, self.end_time, true);
|
||||
}
|
||||
|
||||
if let Some(recv) = &self.recv {
|
||||
match recv.recv_timeout(Duration::from_millis(10)) {
|
||||
Ok(event) => {
|
||||
self.recv.take();
|
||||
match event {
|
||||
ReplayReadEvent::Done(replay) => {
|
||||
self.loading_replay = true;
|
||||
let map_idx = replay.map_idx;
|
||||
self.replay = Some(replay);
|
||||
if let Some(map) =
|
||||
GameManager::singleton().bind().maps.get(map_idx as usize)
|
||||
{
|
||||
if let Some(scene) = &map.bind().scene {
|
||||
self.base().get_tree().change_scene_to_packed(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
ReplayReadEvent::Error(err) => {
|
||||
godot_error!("Error reading replay: {}", err);
|
||||
PopupQueue::singleton().bind_mut().queue(Popup {
|
||||
title: "Error!".to_string(),
|
||||
message: format!("{}", err),
|
||||
ok: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,26 +118,32 @@ impl StandaloneReplayManager {
|
||||
}
|
||||
|
||||
pub fn open_replay(&mut self, path: &GString) {
|
||||
if let Some(mut file) = FileAccess::open(path, ModeFlags::READ) {
|
||||
let mut bytes = Vec::new();
|
||||
while !file.eof_reached() {
|
||||
bytes.extend(file.get_buffer(1_000_000).to_vec());
|
||||
if self.recv.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let path = path.to_string();
|
||||
let (send, recv) = channel();
|
||||
self.recv = Some(recv);
|
||||
|
||||
PopupQueue::singleton().bind_mut().queue(Popup {
|
||||
title: "Loading".to_string(),
|
||||
message: "loading replay".to_string(),
|
||||
ok: false,
|
||||
});
|
||||
|
||||
thread::spawn(move || match fs::read(path) {
|
||||
Ok(mut bytes) => {
|
||||
let cursor = Cursor::new(&mut bytes);
|
||||
let decoder = GzDecoder::new(cursor);
|
||||
|
||||
if let Ok(res) = ciborium::from_reader::<Replay, _>(decoder) {
|
||||
self.loading_replay = true;
|
||||
let map_idx = res.map_idx;
|
||||
self.replay = Some(res);
|
||||
if let Some(map) = GameManager::singleton().bind().maps.get(map_idx as usize) {
|
||||
if let Some(scene) = &map.bind().scene {
|
||||
self.base().get_tree().change_scene_to_packed(scene);
|
||||
}
|
||||
}
|
||||
match ciborium::from_reader::<Replay, _>(decoder) {
|
||||
Ok(replay) => send.send(ReplayReadEvent::Done(replay)),
|
||||
Err(err) => send.send(ReplayReadEvent::Error(err.to_string())),
|
||||
}
|
||||
}
|
||||
Err(err) => send.send(ReplayReadEvent::Error(err.to_string())),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn on_map_loaded(&mut self, map: Gd<Map>) {
|
||||
@ -562,7 +608,7 @@ impl INode for ReplayRecorder {
|
||||
|
||||
fn process(&mut self, _: f64) {
|
||||
if let Some(recv) = &self.recv {
|
||||
if let Ok(data) = recv.recv() {
|
||||
if let Ok(data) = recv.recv_timeout(Duration::from_millis(10)) {
|
||||
match data {
|
||||
ReplaySaveEvent::Error(err) => self.signals().on_saved().emit(&err),
|
||||
ReplaySaveEvent::Done => self.signals().on_saved().emit(&String::new()),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user