~starkingdoms/starkingdoms

ref: 6f949473ea4886e5054dc2e360af440501a8a0b2 starkingdoms/crates/unified/src/client/server_clock.rs -rw-r--r-- 2.3 KiB
6f949473 — core netcode: fix attachment(2) (i odiot) 4 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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();
    }
}