use std::collections::VecDeque; use std::f32::consts::PI; use std::time::{Duration}; use avian2d::parry::transformation::utils::transform; use bevy_replicon::client::confirm_history::ConfirmHistory; use crate::client::components::{ServerClock, ServerTimeOffset}; use crate::prelude::*; use crate::shared::plugins::TICK_RATE; /// interpolation period in seconds const INTERP: f64 = 0.150; pub fn interpolation_plugin(app: &mut App) { app .add_systems(Update, update_interpolation_info) .add_systems(Update, sync_non_interpolated_transforms) .add_systems(Update, do_interpolation); } #[derive(Component, Debug)] pub struct TranslationInterpolationInfo { pub positions: VecDeque<(f64, Vec2)>, } #[derive(Component, Debug)] pub struct RotationInterpolationInfo { pub last_dt: Duration, pub this_tick_start: bevy::platform::time::Instant, pub last_angular_velocity: f32, pub latest_rotation: f32, pub last_rotation: f32, } fn update_interpolation_info( mut interpolation_pos_query: Query<(Entity, &Position, &mut TranslationInterpolationInfo, &ConfirmHistory), Changed>, mut interpolation_rot_query: Query<(&Rotation, &AngularVelocity, &mut RotationInterpolationInfo), Changed>, server_clock: Res, server_time_offset: Res, ) { for (entity, position, mut info, confirm_history) in interpolation_pos_query.iter_mut() { let now = confirm_history.last_tick().get() as f64 / TICK_RATE - **server_time_offset/* - server_clock.rtt/2.0 - server_clock.time_offset*/; //let now = confirm_history.last_tick().get() as f32 / TICK_RATE as f32; info.positions.push_back((now, position.as_vec2())); let mut last_over_time = 0; for (i, (time, _)) in info.positions.iter().enumerate() { if *time < now - INTERP { last_over_time = i; } } if last_over_time > 0 { //debug!("pop"); info.positions.drain(..last_over_time); } //debug!("{:?}", info.positions) /*if let Some((time, _)) = info.positions.get(0) && now.duration_since(*time) > INTERP { debug!("pop"); pos_info.positions.pop_front(); }*/ } for (rotation, angular_velocity, mut info) in interpolation_rot_query.iter_mut() { info.last_dt = info.this_tick_start.elapsed(); info.this_tick_start = bevy::platform::time::Instant::now(); let avg_angular_velocity = (angular_velocity.0.val_num_f32() + info.last_angular_velocity) / 2.0; let delta_rotation = avg_angular_velocity * info.last_dt.as_secs_f32(); let num_revolutions = (delta_rotation / (2.0*PI)).round(); info.last_rotation = info.latest_rotation; let mut rotation_offset = 0.0; let rotation = rotation.as_radians().val_num_f32(); if delta_rotation + info.last_rotation >= PI { rotation_offset = 2.0*PI; } else if delta_rotation + info.last_rotation < -PI { rotation_offset = -2.0*PI; } info.latest_rotation = rotation + rotation_offset + num_revolutions*2.0*PI; info.last_angular_velocity = angular_velocity.0.val_num_f32(); } } fn sync_non_interpolated_transforms( mut query: Query<(&mut Transform, &Position), (Changed, Without)>, ) { for (mut transform, position) in &mut query { transform.translation = position.as_vec2().extend(0.0); } } fn do_interpolation( mut interpolation_query: Query<(Entity, &mut Transform, &mut TranslationInterpolationInfo, &RotationInterpolationInfo)>, time: Res