bevy_ggrs/snapshot/
set.rs

1use bevy::prelude::*;
2
3use crate::snapshot::{AdvanceWorld, LoadWorld, SaveWorld};
4
5/// Set for ordering systems during the [`LoadWorld`] schedule.
6/// The most common option is [`LoadWorldSet::Data`], which is where [`Component`]
7/// and [`Resource`] snapshots are loaded and applied to the [`World`].
8#[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)]
9pub enum LoadWorldSystems {
10    /// Recreate the [`Entity`] graph as it was during the frame to be rolled back to.
11    /// When this set is complete, all entities that were alive during the snapshot
12    /// frame have been recreated, and any that were not have been removed. If the
13    /// [`Entity`] has changed ID, the new ID will be recorded. All this information will be
14    /// made available in [`RollbackEntityMap`](`crate::RollbackEntityMap`).
15    Entity,
16    /// Flush any deferred operations
17    EntityFlush,
18    /// Recreate the stored information as it was during the frame to be rolled back to.
19    /// When this set is complete, all [`Components`](`Component`) and [`Resources`](`Resource`)
20    /// will be rolled back to their exact state during the snapshot.
21    ///
22    /// NOTE: At this point, [`Entity`] relationships may be broken, see [`LoadWorldSet::Mapping`]
23    /// for when those relationships are fixed.
24    Data,
25    /// Flush any deferred operations
26    DataFlush,
27    /// Update all [`Components`](`Component`) and [`Resources`](`Resource`) to reflect the modified
28    /// state of the rollback when compared to the original snapshot. For example, [`Entities`](`Entity`)
29    /// which had to be recreated could not use the same ID, so any data referring to that ID is now invalid.
30    /// Once this set completes, all data should now be coherent with the [`World`].
31    Mapping,
32}
33
34#[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)]
35pub enum SaveWorldSystems {
36    /// Generate checksums for any tracked data.
37    ///
38    /// Within this set, it is expected that all data which will participate in the
39    /// total checksum recorded for this frame will have updated/created a single [`Entity`]
40    /// with a [`ChecksumPart`](`crate::ChecksumPart`) component, containing its contribution.
41    ///
42    /// The final [`Checksum`](`crate::Checksum`) for the frame will be produced after this set, but before
43    /// the [`Snapshot`](`SaveWorldSet::Snapshot`) set.
44    Checksum,
45    /// Saves a snapshot of the [`World`] in this state for future possible rollback.
46    Snapshot,
47}
48
49#[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)]
50pub enum AdvanceWorldSystems {
51    First,
52    Main,
53    Last,
54}
55
56/// Sets up the [`LoadWorldSet`] and [`SaveWorldSet`] sets, allowing for explicit ordering of
57/// rollback systems across plugins.
58pub struct SnapshotSetPlugin;
59
60impl Plugin for SnapshotSetPlugin {
61    fn build(&self, app: &mut App) {
62        app.configure_sets(
63            LoadWorld,
64            (
65                LoadWorldSystems::Entity,
66                LoadWorldSystems::EntityFlush,
67                LoadWorldSystems::Data,
68                LoadWorldSystems::DataFlush,
69                LoadWorldSystems::Mapping,
70            )
71                .chain(),
72        )
73        .configure_sets(
74            SaveWorld,
75            (SaveWorldSystems::Checksum, SaveWorldSystems::Snapshot).chain(),
76        )
77        .configure_sets(
78            AdvanceWorld,
79            (
80                AdvanceWorldSystems::First,
81                AdvanceWorldSystems::Main,
82                AdvanceWorldSystems::Last,
83            )
84                .chain(),
85        )
86        .add_systems(
87            LoadWorld,
88            ApplyDeferred.in_set(LoadWorldSystems::EntityFlush),
89        )
90        .add_systems(LoadWorld, ApplyDeferred.in_set(LoadWorldSystems::DataFlush))
91        .add_systems(
92            AdvanceWorld,
93            ApplyDeferred
94                .after(AdvanceWorldSystems::First)
95                .before(AdvanceWorldSystems::Main),
96        )
97        .add_systems(
98            AdvanceWorld,
99            ApplyDeferred
100                .after(AdvanceWorldSystems::Main)
101                .before(AdvanceWorldSystems::Last),
102        );
103    }
104}