use std::collections::VecDeque; use std::f64::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 rotations: VecDeque<(f64, f64)> // time and rotation } fn update_interpolation_info( mut interpolation_pos_query: Query<(Entity, &Position, &mut TranslationInterpolationInfo, &ConfirmHistory), Changed>, mut interpolation_rot_query: Query<(&Rotation, &AngularVelocity, &mut RotationInterpolationInfo, &ConfirmHistory), 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; 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 { info.positions.drain(..last_over_time); } } for (rotation, angular_velocity, mut info, confirm_history) in interpolation_rot_query.iter_mut() { let now = confirm_history.last_tick().get() as f64 / TICK_RATE - **server_time_offset; let delta_rotation = angular_velocity.0.to_radians() / TICK_RATE; let num_revolutions = (delta_rotation / (2.0*PI)).round(); let mut rotation_offset = 0.0; let rotation = rotation.as_radians() as f64; if let Some((_, rotation)) = info.rotations.back() { if delta_rotation + rotation >= PI { rotation_offset = 2.0 * PI; } else if delta_rotation + rotation < -PI { rotation_offset = -2.0 * PI; } } info.rotations.push_back((now, rotation + rotation_offset + num_revolutions*2.0*PI)); let mut last_over_time = 0; for (i, (time, _)) in info.rotations.iter().enumerate() { if *time < now - INTERP { last_over_time = i; } } if last_over_time > 0 { info.rotations.drain(..last_over_time); } } } 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