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}