Skip to main content

bevy_time/
virt.rs

1#[cfg(feature = "bevy_reflect")]
2use bevy_reflect::Reflect;
3use core::time::Duration;
4use log::debug;
5
6use crate::{real::Real, time::Time};
7
8/// The virtual game clock representing game time.
9///
10/// A specialization of the [`Time`] structure. **For method documentation, see
11/// [`Time<Virtual>#impl-Time<Virtual>`].**
12///
13/// Normally used as `Time<Virtual>`. It is automatically inserted as a resource
14/// by [`TimePlugin`](crate::TimePlugin) and updated based on
15/// [`Time<Real>`](Real). The virtual clock is automatically set as the default
16/// generic [`Time`] resource for the update.
17///
18/// The virtual clock differs from real time clock in that it can be paused, sped up
19/// and slowed down. It also limits how much it can advance in a single update
20/// in order to prevent unexpected behavior in cases where updates do not happen
21/// at regular intervals (e.g. coming back after the program was suspended a long time).
22///
23/// The virtual clock can be paused by calling [`pause()`](Time::pause),
24/// unpaused by calling [`unpause()`](Time::unpause), or toggled by calling
25/// [`toggle()`](Time::toggle). When the game clock is
26/// paused [`delta()`](Time::delta) will be zero on each update, and
27/// [`elapsed()`](Time::elapsed) will not grow.
28/// [`effective_speed()`](Time::effective_speed) will return `0.0`. Calling
29/// [`pause()`](Time::pause) will not affect value the [`delta()`](Time::delta)
30/// value for the update currently being processed.
31///
32/// The speed of the virtual clock can be changed by calling
33/// [`set_relative_speed()`](Time::set_relative_speed). A value of `2.0` means
34/// that virtual clock should advance twice as fast as real time, meaning that
35/// [`delta()`](Time::delta) values will be double of what
36/// [`Time<Real>::delta()`](Time::delta) reports and
37/// [`elapsed()`](Time::elapsed) will go twice as fast as
38/// [`Time<Real>::elapsed()`](Time::elapsed). Calling
39/// [`set_relative_speed()`](Time::set_relative_speed) will not affect the
40/// [`delta()`](Time::delta) value for the update currently being processed.
41///
42/// The maximum amount of delta time that can be added by a single update can be
43/// set by [`set_max_delta()`](Time::set_max_delta). This value serves a dual
44/// purpose in the virtual clock.
45///
46/// If the game temporarily freezes due to any reason, such as disk access, a
47/// blocking system call, or operating system level suspend, reporting the full
48/// elapsed delta time is likely to cause bugs in game logic. Usually if a
49/// laptop is suspended for an hour, it doesn't make sense to try to simulate
50/// the game logic for the elapsed hour when resuming. Instead it is better to
51/// lose the extra time and pretend a shorter duration of time passed. Setting
52/// [`max_delta()`](Time::max_delta) to a relatively short time means that the
53/// impact on game logic will be minimal.
54///
55/// If the game lags for some reason, meaning that it will take a longer time to
56/// compute a frame than the real time that passes during the computation, then
57/// we would fall behind in processing virtual time. If this situation persists,
58/// and computing a frame takes longer depending on how much virtual time has
59/// passed, the game would enter a "death spiral" where computing each frame
60/// takes longer and longer and the game will appear to freeze. By limiting the
61/// maximum time that can be added at once, we also limit the amount of virtual
62/// time the game needs to compute for each frame. This means that the game will
63/// run slow, and it will run slower than real time, but it will not freeze and
64/// it will recover as soon as computation becomes fast again.
65///
66/// You should set [`max_delta()`](Time::max_delta) to a value that is
67/// approximately the minimum FPS your game should have even if heavily lagged
68/// for a moment. The actual FPS when lagged will be somewhat lower than this,
69/// depending on how much more time it takes to compute a frame compared to real
70/// time. You should also consider how stable your FPS is, as the limit will
71/// also dictate how big of an FPS drop you can accept without losing time and
72/// falling behind real time.
73#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Virtual {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f, "Virtual",
            "max_delta", &self.max_delta, "paused", &self.paused,
            "relative_speed", &self.relative_speed, "effective_speed",
            &&self.effective_speed)
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for Virtual { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Virtual {
    #[inline]
    fn clone(&self) -> Virtual {
        let _: ::core::clone::AssertParamIsClone<Duration>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        let _: ::core::clone::AssertParamIsClone<f64>;
        *self
    }
}Clone)]
74#[cfg_attr(feature = "bevy_reflect", derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for Virtual where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Duration as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <bool as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <f64 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for Virtual where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<Duration>("max_delta"),
                                                bevy_reflect::NamedField::new::<bool>("paused"),
                                                bevy_reflect::NamedField::new::<f64>("relative_speed"),
                                                bevy_reflect::NamedField::new::<f64>("effective_speed")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for Virtual where  {
            fn type_path() -> &'static str { "bevy_time::virt::Virtual" }
            fn short_type_path() -> &'static str { "Virtual" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("Virtual")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_time::virt".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_time::virt")
            }
        }
        impl bevy_reflect::Reflect for Virtual where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        impl bevy_reflect::structs::Struct for Virtual where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "max_delta" =>
                        ::core::option::Option::Some(&self.max_delta),
                    "paused" => ::core::option::Option::Some(&self.paused),
                    "relative_speed" =>
                        ::core::option::Option::Some(&self.relative_speed),
                    "effective_speed" =>
                        ::core::option::Option::Some(&self.effective_speed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "max_delta" =>
                        ::core::option::Option::Some(&mut self.max_delta),
                    "paused" => ::core::option::Option::Some(&mut self.paused),
                    "relative_speed" =>
                        ::core::option::Option::Some(&mut self.relative_speed),
                    "effective_speed" =>
                        ::core::option::Option::Some(&mut self.effective_speed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.max_delta),
                    1usize => ::core::option::Option::Some(&self.paused),
                    2usize =>
                        ::core::option::Option::Some(&self.relative_speed),
                    3usize =>
                        ::core::option::Option::Some(&self.effective_speed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.max_delta),
                    1usize => ::core::option::Option::Some(&mut self.paused),
                    2usize =>
                        ::core::option::Option::Some(&mut self.relative_speed),
                    3usize =>
                        ::core::option::Option::Some(&mut self.effective_speed),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("max_delta"),
                    1usize => ::core::option::Option::Some("paused"),
                    2usize => ::core::option::Option::Some("relative_speed"),
                    3usize => ::core::option::Option::Some("effective_speed"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "max_delta" => ::core::option::Option::Some(0usize),
                    "paused" => ::core::option::Option::Some(1usize),
                    "relative_speed" => ::core::option::Option::Some(2usize),
                    "effective_speed" => ::core::option::Option::Some(3usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 4usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("max_delta",
                    bevy_reflect::PartialReflect::to_dynamic(&self.max_delta));
                dynamic.insert_boxed("paused",
                    bevy_reflect::PartialReflect::to_dynamic(&self.paused));
                dynamic.insert_boxed("relative_speed",
                    bevy_reflect::PartialReflect::to_dynamic(&self.relative_speed));
                dynamic.insert_boxed("effective_speed",
                    bevy_reflect::PartialReflect::to_dynamic(&self.effective_speed));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for Virtual where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for Virtual where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let __this =
                        Self {
                            max_delta: <Duration as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "max_delta")?)?,
                            paused: <bool as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "paused")?)?,
                            relative_speed: <f64 as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "relative_speed")?)?,
                            effective_speed: <f64 as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "effective_speed")?)?,
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect), reflect(Clone))]
75pub struct Virtual {
76    max_delta: Duration,
77    paused: bool,
78    relative_speed: f64,
79    effective_speed: f64,
80}
81
82impl Time<Virtual> {
83    /// The default amount of time that can added in a single update.
84    ///
85    /// Equal to 250 milliseconds.
86    const DEFAULT_MAX_DELTA: Duration = Duration::from_millis(250);
87
88    /// Create new virtual clock with given maximum delta step [`Duration`]
89    ///
90    /// # Panics
91    ///
92    /// Panics if `max_delta` is zero.
93    pub fn from_max_delta(max_delta: Duration) -> Self {
94        let mut ret = Self::default();
95        ret.set_max_delta(max_delta);
96        ret
97    }
98
99    /// Returns the maximum amount of time that can be added to this clock by a
100    /// single update, as [`Duration`].
101    ///
102    /// This is the maximum value [`Self::delta()`] will return and also to
103    /// maximum time [`Self::elapsed()`] will be increased by in a single
104    /// update.
105    ///
106    /// This ensures that even if no updates happen for an extended amount of time,
107    /// the clock will not have a sudden, huge advance all at once. This also indirectly
108    /// limits the maximum number of fixed update steps that can run in a single update.
109    ///
110    /// The default value is 250 milliseconds.
111    #[inline]
112    pub fn max_delta(&self) -> Duration {
113        self.context().max_delta
114    }
115
116    /// Sets the maximum amount of time that can be added to this clock by a
117    /// single update, as [`Duration`].
118    ///
119    /// This is the maximum value [`Self::delta()`] will return and also to
120    /// maximum time [`Self::elapsed()`] will be increased by in a single
121    /// update.
122    ///
123    /// This is used to ensure that even if the game freezes for a few seconds,
124    /// or is suspended for hours or even days, the virtual clock doesn't
125    /// suddenly jump forward for that full amount, which would likely cause
126    /// gameplay bugs or having to suddenly simulate all the intervening time.
127    ///
128    /// If no updates happen for an extended amount of time, this limit prevents
129    /// having a sudden, huge advance all at once. This also indirectly limits
130    /// the maximum number of fixed update steps that can run in a single
131    /// update.
132    ///
133    /// The default value is 250 milliseconds. If you want to disable this
134    /// feature, set the value to [`Duration::MAX`].
135    ///
136    /// # Panics
137    ///
138    /// Panics if `max_delta` is zero.
139    #[inline]
140    pub fn set_max_delta(&mut self, max_delta: Duration) {
141        match (&(max_delta), &(Duration::ZERO)) {
    (left_val, right_val) => {
        if *left_val == *right_val {
            let kind = ::core::panicking::AssertKind::Ne;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::Some(format_args!("tried to set max delta to zero")));
        }
    }
};assert_ne!(max_delta, Duration::ZERO, "tried to set max delta to zero");
142        self.context_mut().max_delta = max_delta;
143    }
144
145    /// Returns the speed the clock advances relative to your system clock, as [`f32`].
146    /// This is known as "time scaling" or "time dilation" in other engines.
147    #[inline]
148    pub fn relative_speed(&self) -> f32 {
149        self.relative_speed_f64() as f32
150    }
151
152    /// Returns the speed the clock advances relative to your system clock, as [`f64`].
153    /// This is known as "time scaling" or "time dilation" in other engines.
154    #[inline]
155    pub fn relative_speed_f64(&self) -> f64 {
156        self.context().relative_speed
157    }
158
159    /// Returns the speed the clock advanced relative to your system clock in
160    /// this update, as [`f32`].
161    ///
162    /// Returns `0.0` if the game was paused or what the `relative_speed` value
163    /// was at the start of this update.
164    #[inline]
165    pub fn effective_speed(&self) -> f32 {
166        self.context().effective_speed as f32
167    }
168
169    /// Returns the speed the clock advanced relative to your system clock in
170    /// this update, as [`f64`].
171    ///
172    /// Returns `0.0` if the game was paused or what the `relative_speed` value
173    /// was at the start of this update.
174    #[inline]
175    pub fn effective_speed_f64(&self) -> f64 {
176        self.context().effective_speed
177    }
178
179    /// Sets the speed the clock advances relative to your system clock, given as an [`f32`].
180    ///
181    /// For example, setting this to `2.0` will make the clock advance twice as fast as your system
182    /// clock.
183    ///
184    /// # Panics
185    ///
186    /// Panics if `ratio` is negative or not finite.
187    #[inline]
188    pub fn set_relative_speed(&mut self, ratio: f32) {
189        self.set_relative_speed_f64(ratio as f64);
190    }
191
192    /// Sets the speed the clock advances relative to your system clock, given as an [`f64`].
193    ///
194    /// For example, setting this to `2.0` will make the clock advance twice as fast as your system
195    /// clock.
196    ///
197    /// # Panics
198    ///
199    /// Panics if `ratio` is negative or not finite.
200    #[inline]
201    pub fn set_relative_speed_f64(&mut self, ratio: f64) {
202        if !ratio.is_finite() {
    {
        ::core::panicking::panic_fmt(format_args!("tried to go infinitely fast"));
    }
};assert!(ratio.is_finite(), "tried to go infinitely fast");
203        if !(ratio >= 0.0) {
    {
        ::core::panicking::panic_fmt(format_args!("tried to go back in time"));
    }
};assert!(ratio >= 0.0, "tried to go back in time");
204        self.context_mut().relative_speed = ratio;
205    }
206
207    /// Stops the clock if it is running, otherwise resumes the clock.
208    #[inline]
209    pub fn toggle(&mut self) {
210        self.context_mut().paused ^= true;
211    }
212
213    /// Stops the clock, preventing it from advancing until resumed.
214    #[inline]
215    pub fn pause(&mut self) {
216        self.context_mut().paused = true;
217    }
218
219    /// Resumes the clock.
220    #[inline]
221    pub fn unpause(&mut self) {
222        self.context_mut().paused = false;
223    }
224
225    /// Returns `true` if the clock is currently paused.
226    #[inline]
227    pub fn is_paused(&self) -> bool {
228        self.context().paused
229    }
230
231    /// Returns `true` if the clock was paused at the start of this update.
232    #[inline]
233    pub fn was_paused(&self) -> bool {
234        self.context().effective_speed == 0.0
235    }
236
237    /// Updates the elapsed duration of `self` by `raw_delta`, up to the `max_delta`.
238    fn advance_with_raw_delta(&mut self, raw_delta: Duration) {
239        let max_delta = self.context().max_delta;
240        let clamped_delta = if raw_delta > max_delta {
241            {
    {
        let lvl = ::log::Level::Debug;
        if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
            ::log::__private_api::log({ ::log::__private_api::GlobalLogger },
                format_args!("delta time larger than maximum delta, clamping delta to {0:?} and skipping {1:?}",
                    max_delta, raw_delta - max_delta), lvl,
                &("bevy_time::virt", "bevy_time::virt",
                        ::log::__private_api::loc()), ());
        }
    }
};debug!(
242                "delta time larger than maximum delta, clamping delta to {:?} and skipping {:?}",
243                max_delta,
244                raw_delta - max_delta
245            );
246            max_delta
247        } else {
248            raw_delta
249        };
250        let effective_speed = if self.context().paused {
251            0.0
252        } else {
253            self.context().relative_speed
254        };
255        let delta = if effective_speed != 1.0 {
256            clamped_delta.mul_f64(effective_speed)
257        } else {
258            // avoid rounding when at normal speed
259            clamped_delta
260        };
261        self.context_mut().effective_speed = effective_speed;
262        self.advance_by(delta);
263    }
264}
265
266impl Default for Virtual {
267    fn default() -> Self {
268        Self {
269            max_delta: Time::<Virtual>::DEFAULT_MAX_DELTA,
270            paused: false,
271            relative_speed: 1.0,
272            effective_speed: 1.0,
273        }
274    }
275}
276
277/// Advances [`Time<Virtual>`] and [`Time`] based on the elapsed [`Time<Real>`].
278///
279/// The virtual time will be advanced up to the provided [`Time::max_delta`].
280pub fn update_virtual_time(current: &mut Time, virt: &mut Time<Virtual>, real: &Time<Real>) {
281    let raw_delta = real.delta();
282    virt.advance_with_raw_delta(raw_delta);
283    *current = virt.as_generic();
284}
285
286#[cfg(test)]
287mod test {
288    use super::*;
289
290    #[test]
291    fn test_default() {
292        let time = Time::<Virtual>::default();
293
294        assert!(!time.is_paused()); // false
295        assert_eq!(time.relative_speed(), 1.0);
296        assert_eq!(time.max_delta(), Time::<Virtual>::DEFAULT_MAX_DELTA);
297        assert_eq!(time.delta(), Duration::ZERO);
298        assert_eq!(time.elapsed(), Duration::ZERO);
299    }
300
301    #[test]
302    fn test_advance() {
303        let mut time = Time::<Virtual>::default();
304
305        time.advance_with_raw_delta(Duration::from_millis(125));
306
307        assert_eq!(time.delta(), Duration::from_millis(125));
308        assert_eq!(time.elapsed(), Duration::from_millis(125));
309
310        time.advance_with_raw_delta(Duration::from_millis(125));
311
312        assert_eq!(time.delta(), Duration::from_millis(125));
313        assert_eq!(time.elapsed(), Duration::from_millis(250));
314
315        time.advance_with_raw_delta(Duration::from_millis(125));
316
317        assert_eq!(time.delta(), Duration::from_millis(125));
318        assert_eq!(time.elapsed(), Duration::from_millis(375));
319
320        time.advance_with_raw_delta(Duration::from_millis(125));
321
322        assert_eq!(time.delta(), Duration::from_millis(125));
323        assert_eq!(time.elapsed(), Duration::from_millis(500));
324    }
325
326    #[test]
327    fn test_relative_speed() {
328        let mut time = Time::<Virtual>::default();
329
330        time.advance_with_raw_delta(Duration::from_millis(250));
331
332        assert_eq!(time.relative_speed(), 1.0);
333        assert_eq!(time.effective_speed(), 1.0);
334        assert_eq!(time.delta(), Duration::from_millis(250));
335        assert_eq!(time.elapsed(), Duration::from_millis(250));
336
337        time.set_relative_speed_f64(2.0);
338
339        assert_eq!(time.relative_speed(), 2.0);
340        assert_eq!(time.effective_speed(), 1.0);
341
342        time.advance_with_raw_delta(Duration::from_millis(250));
343
344        assert_eq!(time.relative_speed(), 2.0);
345        assert_eq!(time.effective_speed(), 2.0);
346        assert_eq!(time.delta(), Duration::from_millis(500));
347        assert_eq!(time.elapsed(), Duration::from_millis(750));
348
349        time.set_relative_speed_f64(0.5);
350
351        assert_eq!(time.relative_speed(), 0.5);
352        assert_eq!(time.effective_speed(), 2.0);
353
354        time.advance_with_raw_delta(Duration::from_millis(250));
355
356        assert_eq!(time.relative_speed(), 0.5);
357        assert_eq!(time.effective_speed(), 0.5);
358        assert_eq!(time.delta(), Duration::from_millis(125));
359        assert_eq!(time.elapsed(), Duration::from_millis(875));
360    }
361
362    #[test]
363    fn test_pause() {
364        let mut time = Time::<Virtual>::default();
365
366        time.advance_with_raw_delta(Duration::from_millis(250));
367
368        assert!(!time.is_paused()); // false
369        assert!(!time.was_paused()); // false
370        assert_eq!(time.relative_speed(), 1.0);
371        assert_eq!(time.effective_speed(), 1.0);
372        assert_eq!(time.delta(), Duration::from_millis(250));
373        assert_eq!(time.elapsed(), Duration::from_millis(250));
374
375        time.pause();
376
377        assert!(time.is_paused()); // true
378        assert!(!time.was_paused()); // false
379        assert_eq!(time.relative_speed(), 1.0);
380        assert_eq!(time.effective_speed(), 1.0);
381
382        time.advance_with_raw_delta(Duration::from_millis(250));
383
384        assert!(time.is_paused()); // true
385        assert!(time.was_paused()); // true
386        assert_eq!(time.relative_speed(), 1.0);
387        assert_eq!(time.effective_speed(), 0.0);
388        assert_eq!(time.delta(), Duration::ZERO);
389        assert_eq!(time.elapsed(), Duration::from_millis(250));
390
391        time.unpause();
392
393        assert!(!time.is_paused()); // false
394        assert!(time.was_paused()); // true
395        assert_eq!(time.relative_speed(), 1.0);
396        assert_eq!(time.effective_speed(), 0.0);
397
398        time.advance_with_raw_delta(Duration::from_millis(250));
399
400        assert!(!time.is_paused()); // false
401        assert!(!time.was_paused()); // false
402        assert_eq!(time.relative_speed(), 1.0);
403        assert_eq!(time.effective_speed(), 1.0);
404        assert_eq!(time.delta(), Duration::from_millis(250));
405        assert_eq!(time.elapsed(), Duration::from_millis(500));
406    }
407
408    #[test]
409    fn test_max_delta() {
410        let mut time = Time::<Virtual>::default();
411        time.set_max_delta(Duration::from_millis(500));
412
413        time.advance_with_raw_delta(Duration::from_millis(250));
414
415        assert_eq!(time.delta(), Duration::from_millis(250));
416        assert_eq!(time.elapsed(), Duration::from_millis(250));
417
418        time.advance_with_raw_delta(Duration::from_millis(500));
419
420        assert_eq!(time.delta(), Duration::from_millis(500));
421        assert_eq!(time.elapsed(), Duration::from_millis(750));
422
423        time.advance_with_raw_delta(Duration::from_millis(750));
424
425        assert_eq!(time.delta(), Duration::from_millis(500));
426        assert_eq!(time.elapsed(), Duration::from_millis(1250));
427
428        time.set_max_delta(Duration::from_secs(1));
429
430        assert_eq!(time.max_delta(), Duration::from_secs(1));
431
432        time.advance_with_raw_delta(Duration::from_millis(750));
433
434        assert_eq!(time.delta(), Duration::from_millis(750));
435        assert_eq!(time.elapsed(), Duration::from_millis(2000));
436
437        time.advance_with_raw_delta(Duration::from_millis(1250));
438
439        assert_eq!(time.delta(), Duration::from_millis(1000));
440        assert_eq!(time.elapsed(), Duration::from_millis(3000));
441    }
442}