use bevy::prelude::{Component, Query, ResMut};
use tracing::{info, trace, warn};
use crate::client::components::{ComponentSyncMode, SyncComponent};
use crate::client::interpolation::interpolation_history::ConfirmedHistory;
use crate::client::interpolation::InterpolatedComponent;
use crate::client::resource::Client;
use crate::protocol::Protocol;
use crate::shared::tick_manager::Tick;
const SEND_INTERVAL_TICK_FACTOR: f32 = 1.5;
#[derive(Component, PartialEq, Debug)]
pub struct InterpolateStatus<C: SyncComponent> {
pub start: Option<(Tick, C)>,
pub end: Option<(Tick, C)>,
pub current: Tick,
}
pub(crate) fn update_interpolate_status<C: SyncComponent, P: Protocol>(
client: ResMut<Client<P>>,
mut query: Query<(&mut C, &mut InterpolateStatus<C>, &mut ConfirmedHistory<C>)>,
) {
if C::mode() != ComponentSyncMode::Full {
return;
}
if !client.is_synced() {
return;
}
let send_interval_delta_tick =
(SEND_INTERVAL_TICK_FACTOR * client.config().shared.server_send_interval.as_secs_f32()
/ client.config().shared.tick.tick_duration.as_secs_f32()) as i16
+ 1;
let current_interpolate_tick = client.interpolation_tick();
for (mut component, mut status, mut history) in query.iter_mut() {
let mut start = status.start.take();
let mut end = status.end.take();
if let Some((end_tick, ref end_value)) = end {
if end_tick <= current_interpolate_tick {
start = end.clone();
*component = end_value.clone();
end = None;
}
}
let new_start = history.pop_until_tick(current_interpolate_tick);
if let Some((new_tick, _)) = new_start {
if start.as_ref().map_or(true, |(tick, _)| *tick < new_tick) {
start = new_start;
}
}
if let Some((new_tick, _)) = history.peek() {
if end.as_ref().map_or(true, |(tick, _)| new_tick < *tick) {
trace!("next value after current_interpolate_tick: {:?}", new_tick);
end = history.pop();
}
}
let temp_start = std::mem::take(&mut start);
if let Some((start_tick, _)) = temp_start {
if current_interpolate_tick - start_tick < send_interval_delta_tick {
start = temp_start;
}
}
trace!(?current_interpolate_tick,
last_received_server_tick = ?client.latest_received_server_tick(),
start_tick = ?start.as_ref().map(|(tick, _)| tick),
end_tick = ?end.as_ref().map(|(tick, _) | tick),
"update_interpolate_status");
status.start = start;
status.end = end;
status.current = current_interpolate_tick;
if status.start.is_none() {
trace!("no lerp start tick");
}
if status.end.is_none() {
}
}
}
pub(crate) fn interpolate<C: InterpolatedComponent>(
mut query: Query<(&mut C, &InterpolateStatus<C>)>,
) {
for (mut component, status) in query.iter_mut() {
if let (Some((start_tick, start_value)), Some((end_tick, end_value))) =
(&status.start, &status.end)
{
if start_tick != end_tick {
let t = (status.current - *start_tick) as f32 / (*end_tick - *start_tick) as f32;
*component = C::lerp(start_value.clone(), end_value.clone(), t);
} else {
*component = start_value.clone();
}
}
}
}
#[cfg(test)]
mod tests {
}