use std::ops::Deref;
use bevy::prelude::GamepadButtonType::C;
use bevy::prelude::{
Commands, Component, DetectChanges, Entity, Query, Ref, RemovedComponents, Res, With, Without,
};
use tracing::{error, info};
use crate::client::components::SyncComponent;
use crate::client::interpolation::ConfirmedHistory;
use crate::client::resource::Client;
use crate::prelude::Named;
use crate::protocol::Protocol;
use crate::shared::tick_manager::Tick;
use crate::utils::ready_buffer::ReadyBuffer;
use super::{ComponentSyncMode, Confirmed, Predicted, Rollback, RollbackState};
#[derive(Debug, PartialEq, Clone)]
pub enum ComponentState<T: SyncComponent> {
Removed,
Updated(T),
}
#[derive(Component, Debug)]
pub struct PredictionHistory<T: SyncComponent> {
pub buffer: ReadyBuffer<Tick, ComponentState<T>>,
}
impl<T: SyncComponent> Default for PredictionHistory<T> {
fn default() -> Self {
Self {
buffer: ReadyBuffer::new(),
}
}
}
impl<T: SyncComponent> PartialEq for PredictionHistory<T> {
fn eq(&self, other: &Self) -> bool {
let mut self_history: Vec<_> = self.buffer.heap.iter().collect();
let mut other_history: Vec<_> = other.buffer.heap.iter().collect();
self_history.sort_by_key(|item| item.key);
other_history.sort_by_key(|item| item.key);
self_history.eq(&other_history)
}
}
impl<T: SyncComponent> PredictionHistory<T> {
pub(crate) fn clear(&mut self) {
self.buffer = ReadyBuffer::new();
}
pub(crate) fn pop_until_tick(&mut self, tick: Tick) -> Option<ComponentState<T>> {
self.buffer.pop_until(&tick).map(|(tick, state)| {
self.buffer.add_item(tick, state.clone());
state
})
}
}
#[allow(clippy::type_complexity)]
pub fn add_component_history<T: SyncComponent + Named, P: Protocol>(
mut commands: Commands,
client: Res<Client<P>>,
predicted_entities: Query<(Entity, Option<Ref<T>>), Without<PredictionHistory<T>>>,
confirmed_entities: Query<(Entity, &Confirmed, Option<Ref<T>>)>,
) {
for (confirmed_entity, confirmed, confirmed_component) in confirmed_entities.iter() {
if let Some(p) = confirmed.predicted {
if let Ok((predicted_entity, predicted_component)) = predicted_entities.get(p) {
if T::mode() == ComponentSyncMode::Full {
if let Some(predicted_component) = predicted_component {
if predicted_component.is_added() {
let mut predicted_entity_mut =
commands.get_entity(predicted_entity).unwrap();
let mut history = PredictionHistory::<T>::default();
history.buffer.add_item(
client.tick(),
ComponentState::Updated(predicted_component.deref().clone()),
);
predicted_entity_mut.insert(history);
}
}
}
if let Some(confirmed_component) = confirmed_component {
if confirmed_component.is_added() {
let mut predicted_entity_mut =
commands.get_entity(predicted_entity).unwrap();
match T::mode() {
ComponentSyncMode::Full => {
let mut history = PredictionHistory::<T>::default();
history.buffer.add_item(
client.tick(),
ComponentState::Updated(confirmed_component.deref().clone()),
);
predicted_entity_mut
.insert((confirmed_component.deref().clone(), history));
}
_ => {
predicted_entity_mut.insert(confirmed_component.deref().clone());
}
}
}
}
}
}
}
}
pub fn update_prediction_history<T: SyncComponent, P: Protocol>(
mut query: Query<(Ref<T>, &mut PredictionHistory<T>)>,
mut removed_component: RemovedComponents<T>,
mut removed_entities: Query<&mut PredictionHistory<T>, Without<T>>,
client: Res<Client<P>>,
rollback: Res<Rollback>,
) {
let tick = match rollback.state {
RollbackState::Default => client.tick(),
RollbackState::ShouldRollback { current_tick } => current_tick,
};
for (component, mut history) in query.iter_mut() {
if component.is_changed() {
history
.buffer
.add_item(tick, ComponentState::Updated(component.clone()));
}
}
for entity in removed_component.read() {
if let Ok(mut history) = removed_entities.get_mut(entity) {
history.buffer.add_item(tick, ComponentState::Removed);
}
}
}
#[allow(clippy::type_complexity)]
pub(crate) fn apply_confirmed_update<T: SyncComponent, P: Protocol>(
client: Res<Client<P>>,
mut predicted_entities: Query<
&mut T,
(
Without<PredictionHistory<T>>,
Without<Confirmed>,
With<Predicted>,
),
>,
confirmed_entities: Query<(&Confirmed, Ref<T>)>,
) {
let latest_server_tick = client.latest_received_server_tick();
for (confirmed_entity, confirmed_component) in confirmed_entities.iter() {
if let Some(p) = confirmed_entity.predicted {
if confirmed_component.is_changed() {
if let Ok(mut predicted_component) = predicted_entities.get_mut(p) {
match T::mode() {
ComponentSyncMode::Full => {
error!(
"The predicted entity {:?} should have a ComponentHistory",
p
);
}
ComponentSyncMode::Simple => {
*predicted_component = confirmed_component.deref().clone();
}
ComponentSyncMode::Once => {}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
}