lightyear_core/
timeline.rs1use crate::prelude::Tick;
2use crate::tick::TickDuration;
3use crate::time::{Overstep, TickDelta, TickInstant};
4use bevy_app::{App, FixedFirst, Plugin};
5use bevy_derive::{Deref, DerefMut};
6use bevy_ecs::component::{Component, Mutable};
7use bevy_ecs::entity::Entity;
8use bevy_ecs::event::{EntityEvent, Event};
9use bevy_ecs::prelude::{On, Resource};
10use bevy_ecs::query::With;
11use bevy_ecs::system::{Query, ResMut};
12use bevy_reflect::Reflect;
13use bevy_time::{Fixed, Time};
14use core::ops::{Deref, DerefMut};
15use core::time::Duration;
16#[allow(unused_imports)]
17use tracing::trace;
18
19#[derive(Default, Debug, Clone, Reflect)]
25pub struct Timeline<T: TimelineConfig> {
26 pub context: T::Context,
27 pub now: TickInstant,
28 #[reflect(ignore)]
29 pub marker: core::marker::PhantomData<T>,
30}
31
32pub trait TimelineConfig: Component + Send + Sync + Sized + 'static {
36 type Context;
38
39 type Timeline: NetworkTimeline + Default;
40}
41
42pub trait NetworkTimeline: Component<Mutability = Mutable> {
45 type Config: TimelineConfig;
46 const PAUSED_DURING_ROLLBACK: bool = true;
47
48 fn now(&self) -> TickInstant;
50
51 fn tick(&self) -> Tick;
52
53 fn overstep(&self) -> Overstep;
54
55 fn set_now(&mut self, now: TickInstant);
56
57 fn apply_delta(&mut self, delta: TickDelta);
58
59 fn apply_duration(&mut self, duration: Duration, tick_duration: Duration) {
60 self.apply_delta(TickDelta::from_duration(duration, tick_duration));
61 }
62}
63
64impl<C: TimelineConfig, T: Component<Mutability = Mutable> + DerefMut<Target = Timeline<C>>>
65 NetworkTimeline for T
66{
67 type Config = C;
68
69 fn now(&self) -> TickInstant {
71 self.now
72 }
73
74 fn tick(&self) -> Tick {
75 self.now().tick()
76 }
77
78 fn overstep(&self) -> Overstep {
79 self.now().overstep()
80 }
81
82 fn set_now(&mut self, now: TickInstant) {
83 self.now = now;
84 }
85
86 fn apply_delta(&mut self, delta: TickDelta) {
87 self.now = self.now + delta;
88 }
89}
90
91impl<T: TimelineConfig> Deref for Timeline<T> {
92 type Target = T::Context;
93
94 fn deref(&self) -> &Self::Target {
95 &self.context
96 }
97}
98
99impl<T: TimelineConfig> DerefMut for Timeline<T> {
100 fn deref_mut(&mut self) -> &mut Self::Target {
101 &mut self.context
102 }
103}
104
105#[derive(Resource, Deref, DerefMut, Default, Clone, Reflect)]
109pub struct LocalTimeline {
110 tick: Tick,
111}
112
113impl LocalTimeline {
114 pub fn tick(&self) -> Tick {
116 self.tick
117 }
118
119 pub fn apply_delta(&mut self, delta: i32) {
121 self.tick = self.tick + delta;
122 }
123}
124
125pub(crate) fn increment_local_tick(mut timeline: ResMut<LocalTimeline>) {
127 timeline.tick += 1;
128 trace!(
129 target: "lightyear_debug::timeline",
130 kind = "local_tick",
131 sample_point = "FixedFirst",
132 schedule = "FixedFirst",
133 local_tick = timeline.tick.0,
134 "local timeline tick advanced"
135 );
136}
137
138pub struct NetworkTimelinePlugin<T> {
139 pub(crate) _marker: core::marker::PhantomData<T>,
140}
141
142impl<T> Default for NetworkTimelinePlugin<T> {
143 fn default() -> Self {
144 Self {
145 _marker: core::marker::PhantomData,
146 }
147 }
148}
149
150impl<T: NetworkTimeline> Plugin for NetworkTimelinePlugin<T> {
151 fn build(&self, _: &mut App) {}
152}
153
154#[derive(Event)]
162pub struct SetTickDuration(pub Duration);
163
164pub struct TimelinePlugin {
165 pub(crate) tick_duration: Duration,
166}
167
168impl TimelinePlugin {
169 fn update_tick_duration(trigger: On<SetTickDuration>, mut time: ResMut<Time<Fixed>>) {
170 time.set_timestep(trigger.0);
171 }
172}
173
174impl Plugin for TimelinePlugin {
175 fn build(&self, app: &mut App) {
176 app.init_resource::<LocalTimeline>();
177 app.insert_resource(TickDuration(self.tick_duration));
178 app.world_mut()
179 .resource_mut::<Time<Fixed>>()
180 .set_timestep(self.tick_duration);
181 app.add_observer(Self::update_tick_duration);
182
183 app.add_systems(FixedFirst, increment_local_tick);
184 }
185
186 fn finish(&self, app: &mut App) {
187 app.world_mut().trigger(SetTickDuration(self.tick_duration));
189 }
190}
191
192#[derive(EntityEvent, Debug)]
193pub struct SyncEvent<T: TimelineConfig> {
194 pub entity: Entity,
196 pub tick_delta: i32,
201 marker: core::marker::PhantomData<T>,
202}
203
204impl<T: TimelineConfig> SyncEvent<T> {
205 pub fn new(entity: Entity, tick_delta: i32) -> Self {
206 SyncEvent {
207 entity,
208 tick_delta,
209 marker: core::marker::PhantomData,
210 }
211 }
212}
213
214impl<T: TimelineConfig> Clone for SyncEvent<T> {
215 fn clone(&self) -> Self {
216 *self
217 }
218}
219
220impl<T: TimelineConfig> Copy for SyncEvent<T> {}
221
222#[derive(Component, Debug, Clone, Copy)]
226pub enum Rollback {
227 FromState,
230 FromInputs,
234}
235
236pub fn is_in_rollback(client: Query<(), With<Rollback>>) -> bool {
238 client.single().is_ok()
239}