use crate::prelude::Tick;
use crate::tick::TickDuration;
use crate::time::{Overstep, TickDelta, TickInstant};
use bevy_app::{App, FixedFirst, Plugin};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::component::{Component, Mutable};
use bevy_ecs::event::Event;
use bevy_ecs::observer::Trigger;
use bevy_ecs::query::With;
use bevy_ecs::system::{Query, ResMut};
use bevy_reflect::Reflect;
use bevy_time::{Fixed, Time};
use core::ops::{Deref, DerefMut};
use core::time::Duration;
#[derive(Default, Debug, Clone, Reflect)]
pub struct Timeline<T: TimelineContext> {
pub context: T,
pub now: TickInstant,
#[reflect(ignore)]
pub marker: core::marker::PhantomData<T>,
}
impl<T: TimelineContext> From<T> for Timeline<T> {
fn from(value: T) -> Self {
Self {
context: value,
now: Default::default(),
marker: Default::default(),
}
}
}
pub trait TimelineContext: Send + Sync + 'static {}
pub trait NetworkTimeline: Component<Mutability = Mutable> {
const PAUSED_DURING_ROLLBACK: bool = true;
fn now(&self) -> TickInstant;
fn tick(&self) -> Tick;
fn overstep(&self) -> Overstep;
fn apply_delta(&mut self, delta: TickDelta);
fn apply_duration(&mut self, duration: Duration, tick_duration: Duration) {
self.apply_delta(TickDelta::from_duration(duration, tick_duration));
}
}
impl<C: TimelineContext, T: Component<Mutability = Mutable> + DerefMut<Target = Timeline<C>>>
NetworkTimeline for T
{
fn now(&self) -> TickInstant {
self.now
}
fn tick(&self) -> Tick {
self.now().tick
}
fn overstep(&self) -> Overstep {
self.now().overstep
}
fn apply_delta(&mut self, delta: TickDelta) {
self.now = self.now + delta;
}
}
impl<T: TimelineContext> Deref for Timeline<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.context
}
}
impl<T: TimelineContext> DerefMut for Timeline<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.context
}
}
#[derive(Default, Clone, Reflect)]
pub struct Local;
impl TimelineContext for Local {}
#[derive(Component, Deref, DerefMut, Default, Clone, Reflect)]
pub struct LocalTimeline(Timeline<Local>);
pub(crate) fn increment_local_tick(mut query: Query<&mut LocalTimeline>) {
query.iter_mut().for_each(|mut t| {
t.apply_delta(TickDelta::from_i16(1));
})
}
pub struct NetworkTimelinePlugin<T> {
pub(crate) _marker: core::marker::PhantomData<T>,
}
impl<T> Default for NetworkTimelinePlugin<T> {
fn default() -> Self {
Self {
_marker: core::marker::PhantomData,
}
}
}
impl<T: NetworkTimeline> Plugin for NetworkTimelinePlugin<T> {
fn build(&self, _: &mut App) {}
}
#[derive(Event)]
pub struct SetTickDuration(pub Duration);
pub struct TimelinePlugin {
pub(crate) tick_duration: Duration,
}
impl TimelinePlugin {
fn update_tick_duration(trigger: Trigger<SetTickDuration>, mut time: ResMut<Time<Fixed>>) {
time.set_timestep(trigger.0);
}
}
impl Plugin for TimelinePlugin {
fn build(&self, app: &mut App) {
app.register_type::<LocalTimeline>();
app.insert_resource(TickDuration(self.tick_duration));
app.world_mut()
.resource_mut::<Time<Fixed>>()
.set_timestep(self.tick_duration);
app.add_observer(Self::update_tick_duration);
app.add_plugins(NetworkTimelinePlugin::<LocalTimeline>::default());
app.add_systems(FixedFirst, increment_local_tick);
}
fn finish(&self, app: &mut App) {
app.world_mut().trigger(SetTickDuration(self.tick_duration));
}
}
#[derive(Event, Debug)]
pub struct SyncEvent<T> {
pub tick_delta: i16,
pub marker: core::marker::PhantomData<T>,
}
impl<T: TimelineContext> SyncEvent<T> {
pub fn new(tick_delta: i16) -> Self {
SyncEvent {
tick_delta,
marker: core::marker::PhantomData,
}
}
}
impl<T> Clone for SyncEvent<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SyncEvent<T> {}
#[derive(Component)]
pub enum Rollback {
FromState,
FromInputs,
}
pub fn is_in_rollback(client: Query<(), With<Rollback>>) -> bool {
client.single().is_ok()
}