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