Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to bevy 0.14 #9

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 109 additions & 280 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bevy = {version = "0.13", default_features = false}
bevy = { version = "0.14", default-features = false }
itertools = "0.11.0"
thiserror = "1.0.44"
thiserror = "1.0.44"
6 changes: 4 additions & 2 deletions src/resources.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::FrameNumber;
use bevy::{
ecs::schedule::{InternedScheduleLabel, ScheduleLabel},
ecs::{
intern::Interned,
schedule::{InternedScheduleLabel, ScheduleLabel},
},
prelude::*,
utils::intern::Interned,
};
use std::{collections::VecDeque, ops::Range, time::Duration};

Expand Down
4 changes: 2 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl TimewarpTraits for App {
}
fn register_blueprint<T: TimewarpComponent>(&mut self) -> &mut Self {
let config = self
.world
.world()
.get_resource::<TimewarpConfig>()
.expect("TimewarpConfig resource expected");
let schedule = config.schedule();
Expand All @@ -72,7 +72,7 @@ impl TimewarpTraits for App {
&mut self,
) -> &mut Self {
let config = self
.world
.world()
.get_resource::<TimewarpConfig>()
.expect("TimewarpConfig resource expected");
let schedule = config.schedule();
Expand Down
74 changes: 40 additions & 34 deletions tests/basic_rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn basic_rollback() {

// doing initial spawning here instead of a system in Setup, so we can grab entity ids:
let e1 = app
.world
.world_mut()
.spawn((
Enemy { health: 10 },
EntName {
Expand All @@ -63,7 +63,7 @@ fn basic_rollback() {
))
.id();
let e2 = app
.world
.world_mut()
.spawn((
Enemy { health: 3 },
EntName {
Expand All @@ -73,23 +73,23 @@ fn basic_rollback() {
.id();

assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
0
);

tick(&mut app); // frame 1
assert_eq!(app.world.get::<Enemy>(e1).unwrap().health, 9);
assert_eq!(app.world.get::<Enemy>(e2).unwrap().health, 2);
assert_eq!(app.world().get::<Enemy>(e1).unwrap().health, 9);
assert_eq!(app.world().get::<Enemy>(e2).unwrap().health, 2);
// first tick after spawning, the timewarp components should have been added:
assert!(app.world.get::<ComponentHistory<Enemy>>(e1).is_some());
assert!(app.world.get::<ComponentHistory<Enemy>>(e2).is_some());
assert!(app.world.get::<ServerSnapshot<Enemy>>(e1).is_some());
assert!(app.world.get::<ServerSnapshot<Enemy>>(e2).is_some());
assert!(app.world().get::<ComponentHistory<Enemy>>(e1).is_some());
assert!(app.world().get::<ComponentHistory<Enemy>>(e2).is_some());
assert!(app.world().get::<ServerSnapshot<Enemy>>(e1).is_some());
assert!(app.world().get::<ServerSnapshot<Enemy>>(e2).is_some());
// and contain the correct values from this frame:
// let ch_e1 = app.world.get::<ComponentHistory<Enemy>>(e1).unwrap().values.get(1);
// let ch_e1 = app.world().get::<ComponentHistory<Enemy>>(e1).unwrap().values.get(1);
let ch_e1 = app.comp_val_at::<Enemy>(e1, 1);
assert!(ch_e1.is_some());
assert_eq!(ch_e1.unwrap().health, 9);
Expand All @@ -103,12 +103,12 @@ fn basic_rollback() {
tick(&mut app); // frame 4

// we just simulated frame 4
let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 4);

// by now, these should be current values
assert_eq!(app.world.get::<Enemy>(e1).unwrap().health, 6);
assert_eq!(app.world.get::<Enemy>(e2).unwrap().health, -1);
assert_eq!(app.world().get::<Enemy>(e1).unwrap().health, 6);
assert_eq!(app.world().get::<Enemy>(e2).unwrap().health, -1);

// verify that ComponentHistory is storing values for past frames:
let ch_e1 = app.comp_val_at::<Enemy>(e1, 2);
Expand Down Expand Up @@ -136,23 +136,26 @@ fn basic_rollback() {
// ate a powerup, changing his health to 100.
// our app's netcode would insert the authoritative (slightly outdated) values into ServerSnapshots:

let mut ss_e2 = app.world.get_mut::<ServerSnapshot<Enemy>>(e2).unwrap();
let mut ss_e2 = app
.world_mut()
.get_mut::<ServerSnapshot<Enemy>>(e2)
.unwrap();
ss_e2.insert(2, Enemy { health: 100 }).unwrap();

// this message will be processed in the next tick - frame 5.

let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 4);

tick(&mut app); // frame 5

let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 5);

// frame 5 should run normally, then rollback systems will run, effect a rollback,
// and resimulate from f2
assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
Expand All @@ -176,7 +179,7 @@ fn basic_rollback() {
assert_eq!(ch_e1.unwrap().health, 7);

// resimulation should have brought us back to frame 5.
let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 5);

// frame 2 health was 100,
Expand All @@ -186,13 +189,13 @@ fn basic_rollback() {
let ch_e2 = app.comp_val_at::<Enemy>(e2, 5);
assert!(ch_e2.is_some());
assert_eq!(ch_e2.unwrap().health, 97);
assert_eq!(app.world.get::<Enemy>(e2).unwrap().health, 97);
assert_eq!(app.world().get::<Enemy>(e2).unwrap().health, 97);

tick(&mut app); // frame 6

// should have been a normal frame, no more rollbacks:
assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
Expand All @@ -206,12 +209,15 @@ fn basic_rollback() {
tick(&mut app); // frame 7

assert_eq!(app.comp_val_at::<Enemy>(e2, 7).unwrap().health, 95);
assert_eq!(app.world.get::<Enemy>(e2).unwrap().health, 95);
assert_eq!(app.world().get::<Enemy>(e2).unwrap().health, 95);

// now lets test what happens if we update the server snapshot with what we know to be identical
// values to the the client simulation, to represent a lovely deterministic simulation with no errors

let mut ss_e2 = app.world.get_mut::<ServerSnapshot<Enemy>>(e2).unwrap();
let mut ss_e2 = app
.world_mut()
.get_mut::<ServerSnapshot<Enemy>>(e2)
.unwrap();
// we know from the asserts above that health of e2 was 97 at frame 5.
// so lets make the server confirm that:
ss_e2.insert(5, Enemy { health: 97 }).unwrap();
Expand All @@ -220,7 +226,7 @@ fn basic_rollback() {

// but no - our prediction matches the snapshot so it didn't roll back.
assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
Expand All @@ -230,7 +236,7 @@ fn basic_rollback() {
assert_eq!(app.comp_val_at::<Enemy>(e2, 8).unwrap().health, 94);
assert_eq!(app.comp_val_at::<Enemy>(e2, 7).unwrap().health, 95);

assert_eq!(app.world.get::<Enemy>(e2).unwrap().health, 94);
assert_eq!(app.world().get::<Enemy>(e2).unwrap().health, 94);
}

#[test]
Expand Down Expand Up @@ -261,7 +267,7 @@ fn normal_frames_get_a_chance_to_run_between_rollbacks() {

// doing initial spawning here instead of a system in Setup, so we can grab entity ids:
let e1 = app
.world
.world_mut()
.spawn((
Enemy { health: 10 },
EntName {
Expand All @@ -272,7 +278,7 @@ fn normal_frames_get_a_chance_to_run_between_rollbacks() {
.id();

assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
Expand All @@ -285,14 +291,14 @@ fn normal_frames_get_a_chance_to_run_between_rollbacks() {
tick(&mut app); // frame 4

// we just simulated frame 4
let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 4);

// by now, these should be current values
assert_eq!(app.world.get::<Enemy>(e1).unwrap().health, 6);
assert_eq!(app.world().get::<Enemy>(e1).unwrap().health, 6);

for i in 0..3 {
// let mut ss = app.world.get_mut::<ServerSnapshot<Enemy>>(e1).unwrap();
// let mut ss = app.world().get_mut::<ServerSnapshot<Enemy>>(e1).unwrap();
// ss.insert(
// 2 + i,
// Enemy {
Expand All @@ -302,26 +308,26 @@ fn normal_frames_get_a_chance_to_run_between_rollbacks() {
// .unwrap();

// simulate blueprints arriving in the past every frame, triggering a rollback each time
app.world
app.world_mut()
.entity_mut(e1)
.insert(AssembleBlueprintAtFrame::new(3 + i, FooBlueprint));

tick(&mut app); // tick 5 + i, with rollback.

assert_eq!(
app.world
app.world()
.get_resource::<RollbackStats>()
.unwrap()
.num_rollbacks,
i as u64 + 1
);

let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 5 + i);
}

let gc = app.world.get_resource::<GameClock>().unwrap();
let gc = app.world().get_resource::<GameClock>().unwrap();
assert_eq!(gc.frame(), 7);

assert_eq!(app.world.entity_mut(e1).get::<Bloop>().unwrap().0, 7);
assert_eq!(app.world_mut().entity_mut(e1).get::<Bloop>().unwrap().0, 7);
}
Loading