use std::collections::VecDeque;
use crate::client::components::{ServerClock, ServerTimeOffset};
use crate::prelude::*;
use crate::shared::ecs::clock_sync::{ClientTiming, ServerTiming};
pub fn server_clock_plugin(app: &mut App) {
app
.insert_resource(SyncTimer(Timer::from_seconds(1.0, TimerMode::Repeating)))
.insert_resource(ServerClock {
rtt_queue: VecDeque::with_capacity(10), // 10 seconds
time_offset_queue: VecDeque::with_capacity(10),
..default()
})
.add_systems(Update, send_timing)
.add_systems(Update, recv_timing);
}
#[derive(Resource)]
struct SyncTimer(Timer);
fn send_timing(
mut sync_timer: ResMut<SyncTimer>,
mut client_timing: MessageWriter<ClientTiming>,
time: Res<Time>,
) {
if !sync_timer.0.tick(time.delta()).is_finished() {
return
}
sync_timer.0.reset();
let Ok(now) = web_time::SystemTime::now().duration_since(web_time::UNIX_EPOCH) else {
warn!("Could not get system time");
return
};
client_timing.write(ClientTiming {
time: now.as_secs_f64(),
});
}
fn recv_timing(
mut server_timings: MessageReader<ServerTiming>,
mut server_clock: ResMut<ServerClock>,
mut server_time_offset: ResMut<ServerTimeOffset>,
time: Res<Time>,
) {
for ServerTiming { client_tx, server, server_time_elapsed } in server_timings.read() {
let Ok(now) = web_time::SystemTime::now().duration_since(web_time::UNIX_EPOCH) else {
warn!("Could not get system time");
return
};
let client_rx = now.as_secs_f64();
let time_offset = 2.0*server - client_tx - client_rx;
let rtt = client_rx - client_tx;
if server_clock.rtt_queue.len() >= 10 {
server_clock.rtt_queue.drain(10..);
}
if server_clock.time_offset_queue.len() >= 10 {
server_clock.time_offset_queue.drain(10..);
}
server_clock.rtt_queue.push_back(rtt);
server_clock.time_offset_queue.push_back(time_offset);
server_clock.rtt = server_clock.rtt_queue.iter().sum::<f64>() / server_clock.rtt_queue.len() as f64;
server_clock.time_offset = server_clock.time_offset_queue.iter().sum::<f64>() / server_clock.time_offset_queue.len() as f64;
**server_time_offset = *server_time_elapsed - time.elapsed_secs_f64();
}
}