use bevy_reflect::Reflect;
use core::time::Duration;
use lightyear_core::time::Instant;
use lightyear_utils::ready_buffer::ReadyBuffer;
use rand::RngExt;
#[derive(Clone, Debug, Default, Reflect)]
pub struct LinkConditionerConfig {
pub incoming_latency: Duration,
pub incoming_jitter: Duration,
pub incoming_loss: f32,
}
#[derive(Debug, Clone)]
pub struct LinkConditioner<P: Eq> {
config: LinkConditionerConfig,
pub time_queue: ReadyBuffer<Instant, P>,
}
impl<P: Eq> LinkConditioner<P> {
pub fn new(config: LinkConditionerConfig) -> Self {
LinkConditioner {
config,
time_queue: ReadyBuffer::new(),
}
}
pub(crate) fn condition_packet(&mut self, packet: P, instant: Instant) {
let mut rng = rand::rng();
if rng.random_range(0.0..1.0) <= self.config.incoming_loss {
return;
}
let mut latency: i32 = self.config.incoming_latency.as_millis() as i32;
let mut packet_timestamp = instant;
if self.config.incoming_jitter > Duration::default() {
let jitter: i32 = self.config.incoming_jitter.as_millis() as i32;
latency += rng.random_range(-jitter..jitter);
}
if latency > 0 {
packet_timestamp += Duration::from_millis(latency as u64);
}
self.time_queue.push(packet_timestamp, packet);
}
pub(crate) fn pop_packet(&mut self, instant: Instant) -> Option<P> {
self.time_queue.pop_item(&instant).map(|(_, packet)| packet)
}
}
impl LinkConditionerConfig {
pub fn new(incoming_latency: Duration, incoming_jitter: Duration, incoming_loss: f32) -> Self {
LinkConditionerConfig {
incoming_latency,
incoming_jitter,
incoming_loss,
}
}
pub fn half(self) -> Self {
LinkConditionerConfig {
incoming_latency: self.incoming_latency / 2,
incoming_jitter: self.incoming_jitter / 2,
incoming_loss: self.incoming_loss / 2.0,
}
}
pub fn good_condition() -> Self {
LinkConditionerConfig {
incoming_latency: Duration::from_millis(40),
incoming_jitter: Duration::from_millis(6),
incoming_loss: 0.002,
}
}
pub fn average_condition() -> Self {
LinkConditionerConfig {
incoming_latency: Duration::from_millis(100),
incoming_jitter: Duration::from_millis(15),
incoming_loss: 0.02,
}
}
pub fn poor_condition() -> Self {
LinkConditionerConfig {
incoming_latency: Duration::from_millis(200),
incoming_jitter: Duration::from_millis(30),
incoming_loss: 0.10,
}
}
}