use std::marker::PhantomData;
use std::time::Duration;
use bevy::prelude::{
apply_deferred, App, IntoSystemConfigs, IntoSystemSetConfigs, Plugin, PreUpdate, SystemSet,
};
use crate::client::components::SyncComponent;
use crate::client::interpolation::despawn::{
despawn_interpolated, removed_components, InterpolationMapping,
};
use crate::client::interpolation::interpolate::{interpolate, update_interpolate_status};
use crate::protocol::component::ComponentProtocol;
use crate::protocol::Protocol;
use crate::shared::sets::MainSet;
use super::interpolation_history::{add_component_history, apply_confirmed_update};
use super::{spawn_interpolated_entity, InterpolatedComponent};
#[derive(Clone)]
pub struct InterpolationDelay {
pub min_delay: Duration,
pub send_interval_ratio: f32,
}
impl Default for InterpolationDelay {
fn default() -> Self {
Self {
min_delay: Duration::from_millis(0),
send_interval_ratio: 2.0,
}
}
}
impl InterpolationDelay {
pub fn with_min_delay(mut self, min_delay: Duration) -> Self {
self.min_delay = min_delay;
self
}
pub fn with_send_interval_ratio(mut self, send_interval_ratio: f32) -> Self {
self.send_interval_ratio = send_interval_ratio;
self
}
pub(crate) fn to_duration(&self, server_send_interval: Duration) -> Duration {
let ratio_value = server_send_interval.mul_f32(self.send_interval_ratio);
std::cmp::max(ratio_value, self.min_delay)
}
}
#[derive(Clone)]
pub struct InterpolationConfig {
pub(crate) delay: InterpolationDelay,
}
#[allow(clippy::derivable_impls)]
impl Default for InterpolationConfig {
fn default() -> Self {
Self {
delay: InterpolationDelay::default(),
}
}
}
impl InterpolationConfig {
pub fn with_delay(mut self, delay: InterpolationDelay) -> Self {
self.delay = delay;
self
}
}
pub struct InterpolationPlugin<P: Protocol> {
config: InterpolationConfig,
_marker: PhantomData<P>,
}
impl<P: Protocol> InterpolationPlugin<P> {
pub(crate) fn new(config: InterpolationConfig) -> Self {
Self {
config,
_marker: PhantomData,
}
}
}
impl<P: Protocol> Default for InterpolationPlugin<P> {
fn default() -> Self {
Self {
config: InterpolationConfig::default(),
_marker: PhantomData,
}
}
}
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum InterpolationSet {
SpawnInterpolation,
SpawnInterpolationFlush,
SpawnHistory,
SpawnHistoryFlush,
Despawn,
DespawnFlush,
Interpolate,
}
pub fn add_interpolation_systems<C: SyncComponent, P: Protocol>(app: &mut App) {
app.add_systems(
PreUpdate,
(
(add_component_history::<C, P>).in_set(InterpolationSet::SpawnHistory),
(removed_components::<C>).in_set(InterpolationSet::Despawn),
(
apply_confirmed_update::<C, P>,
update_interpolate_status::<C, P>,
)
.chain()
.in_set(InterpolationSet::Interpolate),
),
);
}
pub fn add_lerp_systems<C: InterpolatedComponent, P: Protocol>(app: &mut App) {
app.add_systems(
PreUpdate,
(interpolate::<C>
.after(update_interpolate_status::<C, P>)
.in_set(InterpolationSet::Interpolate),),
);
}
impl<P: Protocol> Plugin for InterpolationPlugin<P> {
fn build(&self, app: &mut App) {
P::Components::add_interpolation_systems(app);
app.init_resource::<InterpolationMapping>();
app.configure_sets(
PreUpdate,
(
MainSet::Receive,
InterpolationSet::SpawnInterpolation,
InterpolationSet::SpawnInterpolationFlush,
InterpolationSet::SpawnHistory,
InterpolationSet::SpawnHistoryFlush,
InterpolationSet::Despawn,
InterpolationSet::DespawnFlush,
InterpolationSet::Interpolate,
)
.chain(),
);
app.add_systems(
PreUpdate,
(
apply_deferred.in_set(InterpolationSet::SpawnInterpolationFlush),
apply_deferred.in_set(InterpolationSet::SpawnHistoryFlush),
apply_deferred.in_set(InterpolationSet::DespawnFlush),
),
);
app.add_systems(
PreUpdate,
(
spawn_interpolated_entity.in_set(InterpolationSet::SpawnInterpolation),
despawn_interpolated.in_set(InterpolationSet::Despawn),
),
);
}
}