Skip to content
This repository has been archived by the owner on Nov 10, 2024. It is now read-only.

Commit

Permalink
fix error when spawns occur during rb window
Browse files Browse the repository at this point in the history
  • Loading branch information
RJ committed Oct 19, 2023
1 parent 6db9273 commit 9dcb8f4
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 85 deletions.
7 changes: 1 addition & 6 deletions NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ New custom events are written to the bevy event queue, to be consumed by my game
<td>sanity check systems prevent blowing your own foot off, kinda.</td>
</tr>
<tr>
<td>CheckIfRollbackComplete</td>
<td>InRollback</td>
<td>in rb</td>
<td>During rollback, we check if we should exit rollback, having resimulated everything in the requested rollback range.</td>
</tr>
Expand All @@ -148,11 +148,6 @@ the appropriate frame for starting rollback.
</td>
</tr>
<tr>
<td>DuringRollback</td>
<td>in rb</td>
<td>record component removals, revive dead components that should be alive this frame, etc.</td>
</tr>
<tr>
<td>UnwrapBlueprints</td>
<td>always</td>
<td>Unwrap ABAFs for this frame</td>
Expand Down
4 changes: 2 additions & 2 deletions src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ impl<T: TimewarpComponent> ComponentHistory<T> {
false
}
pub fn report_birth_at_frame(&mut self, frame: FrameNumber) {
debug!("component birth @ {frame} {:?}", std::any::type_name::<T>());
trace!("component birth @ {frame} {:?}", std::any::type_name::<T>());
if self.alive_at_frame(frame) {
warn!("Can't report birth of component already alive");
trace!("Can't report birth of component already alive");
return;
}
assert!(
Expand Down
27 changes: 9 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,7 @@ use prelude::*;
pub enum TimewarpPrefixSet {
First,

CheckIfRollbackComplete,

/// Runs during rollback
DuringRollback,
InRollback,

/// Doesn't run in rollback
///
Expand Down Expand Up @@ -277,15 +274,12 @@ impl Plugin for TimewarpPlugin {
self.config.schedule(),
(
TimewarpPrefixSet::First,
TimewarpPrefixSet::CheckIfRollbackComplete
.run_if(resource_exists::<Rollback>()),
TimewarpPrefixSet::InRollback.run_if(resource_exists::<Rollback>()),
// -- apply_deferred -- //
TimewarpPrefixSet::CheckIfRollbackNeeded
.run_if(not(resource_exists::<Rollback>())),
// -- apply_deferred -- //
TimewarpPrefixSet::StartRollback.run_if(resource_added::<Rollback>()),
// -- apply_deferred -- //
TimewarpPrefixSet::DuringRollback.run_if(resource_exists::<Rollback>()),
TimewarpPrefixSet::UnwrapBlueprints,
TimewarpPrefixSet::Last,
// -- apply_deferred -- //
Expand All @@ -298,7 +292,7 @@ impl Plugin for TimewarpPlugin {
.add_systems(
self.config.schedule(),
apply_deferred
.after(TimewarpPrefixSet::CheckIfRollbackComplete)
.after(TimewarpPrefixSet::InRollback)
.before(TimewarpPrefixSet::CheckIfRollbackNeeded),
)
.add_systems(
Expand All @@ -307,12 +301,6 @@ impl Plugin for TimewarpPlugin {
.after(TimewarpPrefixSet::CheckIfRollbackNeeded)
.before(TimewarpPrefixSet::StartRollback),
)
.add_systems(
self.config.schedule(),
apply_deferred
.after(TimewarpPrefixSet::StartRollback)
.before(TimewarpPrefixSet::DuringRollback),
)
//
// END APPLY DEFERREDS
//
Expand All @@ -323,7 +311,10 @@ impl Plugin for TimewarpPlugin {
.add_systems(
self.config.schedule(),
(|game_clock: Res<GameClock>, rb: Option<Res<Rollback>>| {
trace!("Prefix::First for {} {rb:?}", **game_clock + 1)
trace!(
"--------------------- Prefix::First for {} {rb:?}",
**game_clock + 1
)
})
.in_set(TimewarpPrefixSet::First),
)
Expand Down Expand Up @@ -358,11 +349,11 @@ impl Plugin for TimewarpPlugin {
.add_systems(
self.config.schedule(),
(
systems::prefix_check_for_rollback_completion::check_for_rollback_completion,
systems::prefix_in_rollback::check_for_rollback_completion,
apply_deferred,
)
.chain()
.in_set(TimewarpPrefixSet::CheckIfRollbackComplete),
.in_set(TimewarpPrefixSet::InRollback),
)
.add_systems(
self.config.schedule(),
Expand Down
3 changes: 1 addition & 2 deletions src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ pub(crate) mod postfix_during_rollback;
pub(crate) mod postfix_last;

pub(crate) mod prefix_blueprints;
pub(crate) mod prefix_check_for_rollback_completion;
pub(crate) mod prefix_check_if_rollback_needed;
pub(crate) mod prefix_during_rollback;
pub(crate) mod prefix_first;
pub(crate) mod prefix_in_rollback;
pub(crate) mod prefix_start_rollback;

/// footgun protection - in case your clock ticking fn isn't running properly, this avoids
Expand Down
2 changes: 1 addition & 1 deletion src/systems/postfix_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub(crate) fn record_component_birth<T: TimewarpComponent>(
}

for (entity, mut ch) in q.iter_mut() {
debug!(
trace!(
"{entity:?} Component birth @ {:?} {:?}",
game_clock.frame(),
std::any::type_name::<T>()
Expand Down
31 changes: 0 additions & 31 deletions src/systems/prefix_check_for_rollback_completion.rs

This file was deleted.

18 changes: 18 additions & 0 deletions src/systems/prefix_first.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,21 @@ pub(crate) fn enable_error_correction_for_new_component_histories<T: TimewarpCom
ch.enable_correction_logging();
}
}

/// when components are removed, we log the death frame
pub(crate) fn record_component_death<T: TimewarpComponent>(
mut removed: RemovedComponents<T>,
mut q: Query<&mut ComponentHistory<T>>,
game_clock: Res<GameClock>,
) {
for entity in &mut removed {
if let Ok(mut ct) = q.get_mut(entity) {
debug!(
"{entity:?} Component death @ {:?} {:?}",
game_clock.frame(),
std::any::type_name::<T>()
);
ct.report_death_at_frame(game_clock.frame());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,42 @@ use bevy::prelude::*;
*/

/// when components are removed, we log the death frame
pub(crate) fn record_component_death<T: TimewarpComponent>(
mut removed: RemovedComponents<T>,
mut q: Query<&mut ComponentHistory<T>>,
/// If we reached the end of the Rollback range, restore the frame period and cleanup.
/// this will remove the [`Rollback`] resource.
pub(crate) fn check_for_rollback_completion(
game_clock: Res<GameClock>,
rb: Res<Rollback>,
mut commands: Commands,
mut fx: ResMut<FixedTime>,
) {
for entity in &mut removed {
if let Ok(mut ct) = q.get_mut(entity) {
debug!(
"{entity:?} Component death @ {:?} {:?}",
game_clock.frame(),
std::any::type_name::<T>()
);
ct.report_death_at_frame(game_clock.frame());
}
if rb.range.end != **game_clock {
return;
}
// we keep track of the previous rollback mainly for integration tests
commands.insert_resource(PreviousRollback(rb.as_ref().clone()));
info!(
"🛼🛼 Rollback complete. {:?}, frames: {} gc:{game_clock:?}",
rb,
rb.range.end - rb.range.start
);
fx.period = rb.original_period.unwrap();
commands.remove_resource::<Rollback>();
}

/// during rollback, need to re-insert components that were removed, based on stored lifetimes.
pub(crate) fn rebirth_components_during_rollback<T: TimewarpComponent>(
q: Query<(Entity, &ComponentHistory<T>, Option<&OriginFrame>), Without<T>>,
q: Query<(Entity, &ComponentHistory<T>), Without<T>>,
game_clock: Res<GameClock>,
mut commands: Commands,
rb: Res<Rollback>,
) {
for (entity, comp_history, opt_originframe) in q.iter() {
let target_frame = game_clock.frame().max(opt_originframe.map_or(0, |of| of.0));
for (entity, comp_history) in q.iter() {
let target_frame = game_clock.frame();
if comp_history.alive_at_frame(target_frame) {
info!(
"CHecking if {entity:?} {} alive at {game_clock:?} - YES ",
comp_history.type_name()
);
// we could go fishing in SS for this, but it should be here if its alive.
// i think i'm only hitting this with rollback underflows though, during load?
// need more investigation and to figure out a test case..
Expand All @@ -59,6 +67,10 @@ pub(crate) fn rebirth_components_during_rollback<T: TimewarpComponent>(
);
commands.entity(entity).insert(comp_val.clone());
} else {
info!(
"CHecking if {entity:?} {} alive at {game_clock:?} - NO ",
comp_history.type_name()
);
trace!(
"comp not alive at {game_clock:?} for {entity:?} {:?} {}",
comp_history.alive_ranges,
Expand Down
5 changes: 4 additions & 1 deletion src/systems/prefix_start_rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub(crate) fn rollback_component<T: TimewarpComponent>(
**game_clock
};

let end_frame = rb.range.end;

let prefix = if rollback_frame != **game_clock {
warn!(
"😬 rollback_component {entity:?} {game_clock:?} rollback_frame:{rollback_frame} {}",
Expand All @@ -105,9 +107,10 @@ pub(crate) fn rollback_component<T: TimewarpComponent>(
} else {
""
};
trace!("rollback_component {entity:?} {} rollback-frame:{rollback_frame} {game_clock:?} end_frame={end_frame} {rb:?}", comp_hist.type_name());
let provenance = match (
comp_hist.alive_at_frame(rollback_frame),
comp_hist.alive_at_frame(**game_clock),
comp_hist.alive_at_frame(end_frame),
) {
(true, true) => Provenance::AliveThenAlive,
(true, false) => Provenance::AliveThenDead,
Expand Down
13 changes: 5 additions & 8 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,14 @@ impl TimewarpTraits for App {
);
self.add_systems(
schedule.clone(), // TODO RJRJ MOVE FILE
prefix_during_rollback::record_component_death::<T>
prefix_first::record_component_death::<T>
.run_if(not(resource_exists::<Rollback>()))
.in_set(TimewarpPrefixSet::First), // RJRJRJ X
.in_set(TimewarpPrefixSet::First),
);
self.add_systems(
schedule.clone(),
(
// prefix_during_rollback::record_component_death::<T>,
prefix_during_rollback::rebirth_components_during_rollback::<T>,
)
.in_set(TimewarpPrefixSet::DuringRollback),
(prefix_in_rollback::rebirth_components_during_rollback::<T>,)
.in_set(TimewarpPrefixSet::InRollback),
);
// this may result in a Rollback resource being inserted.
self.add_systems(
Expand Down Expand Up @@ -194,7 +191,7 @@ impl TimewarpEntityMutTraits for EntityMut<'_> {
ss.insert(frame, component.clone())
.expect("fresh one can't fail");
// (tw system sets correction logging for us later, if needed)
info!(
debug!(
"Adding SS/CH to {:?} for {}\nInitial val @ {:?} = {:?}",
self.id(),
std::any::type_name::<T>(),
Expand Down
Loading

0 comments on commit 9dcb8f4

Please sign in to comment.