From e779860d7af609e36db17d59505d3cbc9f352054 Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Thu, 22 Aug 2024 07:02:26 -0400 Subject: [PATCH] Upgrade to bevy 0.14 (#37) * upgrade to bevy 0.14 -- some tests failing * don't anticipate double-buffering in tests * clippy * Revert "don't anticipate double-buffering in tests" This reverts commit 0252fc09614f3ed7db1652203a500f7c1b29f857. * Configure playback systems to run after event updates --- Cargo.toml | 4 +- examples/gamepad.rs | 11 +++-- examples/input_capture.rs | 2 +- examples/input_playback.rs | 10 ++-- src/input_capture.rs | 3 +- src/input_playback.rs | 4 +- tests/input_capture.rs | 34 +++++++------- tests/input_playback.rs | 96 +++++++++++++++++++++----------------- 8 files changed, 87 insertions(+), 77 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b394462..ed69962 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,12 +21,12 @@ members = ["./", "tools/ci"] default = [] [dependencies] -bevy = { version = "0.13", default_features = false, features = ["serialize"] } +bevy = { version = "0.14", default-features = false, features = ["serialize"] } serde = { version = "1.0", features = ["derive"] } ron = "0.8" [dev-dependencies] -bevy = { version = "0.13", default_features = true, features = ["serialize"] } +bevy = { version = "0.14", default-features = true, features = ["serialize"] } smol_str = "0.2" [lib] diff --git a/examples/gamepad.rs b/examples/gamepad.rs index 6f470cc..8942f38 100644 --- a/examples/gamepad.rs +++ b/examples/gamepad.rs @@ -109,6 +109,7 @@ mod gamepad_viewer_example { use std::f32::consts::PI; use bevy::{ + color::palettes, input::gamepad::{GamepadButton, GamepadButtonChangedEvent, GamepadEvent, GamepadSettings}, prelude::*, sprite::{MaterialMesh2dBundle, Mesh2dHandle}, @@ -125,11 +126,11 @@ mod gamepad_viewer_example { const STICKS_X: f32 = 150.; const STICKS_Y: f32 = -135.; - const NORMAL_BUTTON_COLOR: Color = Color::rgb(0.2, 0.2, 0.2); - const ACTIVE_BUTTON_COLOR: Color = Color::PURPLE; - const LIVE_COLOR: Color = Color::rgb(0.4, 0.4, 0.4); - const DEAD_COLOR: Color = Color::rgb(0.3, 0.3, 0.3); - const EXTENT_COLOR: Color = Color::rgb(0.3, 0.3, 0.3); + const NORMAL_BUTTON_COLOR: Color = Color::srgb(0.2, 0.2, 0.2); + const ACTIVE_BUTTON_COLOR: Color = Color::Srgba(palettes::css::PURPLE); + const LIVE_COLOR: Color = Color::srgb(0.4, 0.4, 0.4); + const DEAD_COLOR: Color = Color::srgb(0.3, 0.3, 0.3); + const EXTENT_COLOR: Color = Color::srgb(0.3, 0.3, 0.3); const TEXT_COLOR: Color = Color::WHITE; #[derive(Component, Deref)] diff --git a/examples/input_capture.rs b/examples/input_capture.rs index aacaa27..25161c5 100644 --- a/examples/input_capture.rs +++ b/examples/input_capture.rs @@ -3,7 +3,7 @@ use leafwing_input_playback::{ input_capture::InputCapturePlugin, timestamped_input::TimestampedInputs, }; -fn main() { +fn main() -> AppExit { App::new() .add_plugins((DefaultPlugins, InputCapturePlugin)) .add_systems(Update, debug_input_capture) diff --git a/examples/input_playback.rs b/examples/input_playback.rs index 6e4d6c1..f75fac3 100644 --- a/examples/input_playback.rs +++ b/examples/input_playback.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, window::PrimaryWindow}; +use bevy::{color::palettes, prelude::*, window::PrimaryWindow}; use leafwing_input_playback::{ input_capture::{InputCapturePlugin, InputModesCaptured}, @@ -6,14 +6,14 @@ use leafwing_input_playback::{ timestamped_input::TimestampedInputs, }; -fn main() { +fn main() -> AppExit { App::new() .add_plugins((DefaultPlugins, InputCapturePlugin, InputPlaybackPlugin)) // Disable all input capture and playback to start .insert_resource(InputModesCaptured::DISABLE_ALL) .insert_resource(PlaybackStrategy::Paused) // Creates a little game that spawns decaying boxes where the player clicks - .insert_resource(ClearColor(Color::rgb(0.9, 0.9, 0.9))) + .insert_resource(ClearColor(Color::srgb(0.9, 0.9, 0.9))) .add_systems(Startup, setup) .add_systems( Update, @@ -43,7 +43,7 @@ pub fn cursor_pos_as_world_pos( let window_size = Vec2::new(current_window.width(), current_window.height()); // Convert screen position [0..resolution] to ndc [-1..1] - let ndc_to_world = cam_t.compute_matrix() * cam.projection_matrix().inverse(); + let ndc_to_world = cam_t.compute_matrix() * cam.clip_from_view().inverse(); let ndc = (Vec2::new(cursor_pos.x, cursor_pos.y) / window_size) * 2.0 - Vec2::ONE; let world_pos = ndc_to_world.project_point3(ndc.extend(-1.0)); world_pos.truncate() @@ -68,7 +68,7 @@ fn spawn_boxes( commands .spawn(SpriteBundle { sprite: Sprite { - color: Color::DARK_GREEN, + color: Color::Srgba(palettes::css::DARK_GREEN), ..default() }, transform: Transform { diff --git a/src/input_capture.rs b/src/input_capture.rs index 7bdb886..722431b 100644 --- a/src/input_capture.rs +++ b/src/input_capture.rs @@ -28,7 +28,7 @@ pub struct InputCapturePlugin; impl Plugin for InputCapturePlugin { fn build(&self, app: &mut App) { // Avoid double-adding frame_counter - if !app.world.contains_resource::() { + if !app.world().contains_resource::() { app.init_resource::() .add_systems(First, frame_counter); } @@ -178,6 +178,7 @@ pub fn serialize_timestamped_inputs( if let Some(file_path) = playback_file.path() { let mut file = OpenOptions::new() .create(true) + .truncate(true) .write(true) .open(file_path) .expect("Could not open file."); diff --git a/src/input_playback.rs b/src/input_playback.rs index 8b3ed6e..3aaef11 100644 --- a/src/input_playback.rs +++ b/src/input_playback.rs @@ -31,9 +31,9 @@ pub struct InputPlaybackPlugin; impl Plugin for InputPlaybackPlugin { fn build(&self, app: &mut App) { // Avoid double-adding frame_counter - if !app.world.contains_resource::() { + if !app.world().contains_resource::() { app.init_resource::() - .add_systems(First, frame_counter); + .add_systems(First, frame_counter.after(bevy::ecs::event::EventUpdates)); } app.init_resource::() diff --git a/tests/input_capture.rs b/tests/input_capture.rs index 0e389f7..3583511 100644 --- a/tests/input_capture.rs +++ b/tests/input_capture.rs @@ -49,12 +49,12 @@ fn capture_app() -> App { fn capture_sent_events() { let mut app = capture_app(); - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); keyboard_events.send(TEST_RELEASE); app.update(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.len(), 2); } @@ -62,17 +62,17 @@ fn capture_sent_events() { fn identity_of_sent_events() { let mut app = capture_app(); - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); // Events within the same frame are not ordered reliably app.update(); - let mut mouse_events = app.world.resource_mut::>(); + let mut mouse_events = app.world_mut().resource_mut::>(); mouse_events.send(TEST_MOUSE); app.update(); - let mut timestamped_input = app.world.resource_mut::(); + let mut timestamped_input = app.world_mut().resource_mut::(); let mut iterator = timestamped_input.iter_all().into_iter(); let first_event: TimestampedInputEvent = iterator.next().unwrap(); @@ -90,16 +90,16 @@ fn identity_of_sent_events() { fn framecount_of_sent_events() { let mut app = capture_app(); - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); app.update(); - let mut mouse_events = app.world.resource_mut::>(); + let mut mouse_events = app.world_mut().resource_mut::>(); mouse_events.send(TEST_MOUSE); app.update(); - let mut timestamped_input = app.world.resource_mut::(); + let mut timestamped_input = app.world_mut().resource_mut::(); let mut iterator = timestamped_input.iter_all().into_iter(); let first_event: TimestampedInputEvent = iterator.next().expect("Keyboard event failed."); @@ -115,47 +115,47 @@ fn framecount_of_sent_events() { fn toggle_input_capture() { let mut app = capture_app(); - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); keyboard_events.send(TEST_RELEASE); app.update(); // Inputs are captured while input capturing is enabled by default - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.len(), 2); // Disabling input capture - let mut input_modes_captured = app.world.resource_mut::(); + let mut input_modes_captured = app.world_mut().resource_mut::(); *input_modes_captured = InputModesCaptured::DISABLE_ALL; - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); keyboard_events.send(TEST_RELEASE); app.update(); // Inputs are not captured while input capturing is disabled - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.len(), 2); // Partially re-enabling input capture - let mut input_modes_captured = app.world.resource_mut::(); + let mut input_modes_captured = app.world_mut().resource_mut::(); *input_modes_captured = InputModesCaptured { mouse_buttons: false, keyboard: true, ..Default::default() }; - let mut keyboard_events = app.world.resource_mut::>(); + let mut keyboard_events = app.world_mut().resource_mut::>(); keyboard_events.send(TEST_PRESS); - let mut mouse_events = app.world.resource_mut::>(); + let mut mouse_events = app.world_mut().resource_mut::>(); mouse_events.send(TEST_MOUSE); app.update(); // Only the keyboard events (and app exit events) were captured - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.len(), 3); } diff --git a/tests/input_playback.rs b/tests/input_playback.rs index 0e58f76..4417992 100644 --- a/tests/input_playback.rs +++ b/tests/input_playback.rs @@ -1,15 +1,16 @@ // BLOCKED: add time strategy tests: https://github.com/bevyengine/bevy/issues/6146 +use bevy::ecs::event::EventRegistry; use bevy::input::keyboard::Key; use bevy::input::keyboard::KeyboardInput; use bevy::input::ButtonState; use bevy::input::InputPlugin; use bevy::prelude::*; +use bevy::time::TimeUpdateStrategy; use bevy::utils::Duration; - use bevy::window::WindowPlugin; -use leafwing_input_playback::frame_counting::FrameCount; +use leafwing_input_playback::frame_counting::FrameCount; use leafwing_input_playback::input_capture::InputCapturePlugin; use leafwing_input_playback::input_capture::InputModesCaptured; use leafwing_input_playback::input_playback::InputPlaybackPlugin; @@ -39,9 +40,11 @@ fn playback_app(strategy: PlaybackStrategy) -> App { InputPlugin, InputPlaybackPlugin, )); - app.world - .remove_resource::(); - *app.world.resource_mut::() = strategy; + + let mut registry = app.world_mut().resource_mut::(); + registry.should_update = ShouldUpdateEvents::Always; + + *app.world_mut().resource_mut::() = strategy; app } @@ -68,23 +71,24 @@ fn complex_timestamped_input() -> TimestampedInputs { #[test] fn minimal_playback() { let mut app = playback_app(PlaybackStrategy::FrameCount); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 0); - *app.world.resource_mut::() = simple_timestamped_input(); + *app.world_mut().resource_mut::() = simple_timestamped_input(); + app.update(); // By default, only events up to the current frame are played back - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 1); - let input = app.world.resource::>(); + let input = app.world().resource::>(); assert!(input.pressed(KeyCode::KeyF)); app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); // Events are double-buffered assert_eq!(input_events.len(), 2); - let input = app.world.resource::>(); + let input = app.world().resource::>(); assert!(!input.pressed(KeyCode::KeyF)); } @@ -94,17 +98,17 @@ fn capture_and_playback() { app.add_plugins(InputCapturePlugin); app.insert_resource(PlaybackStrategy::Paused); - let mut input_events = app.world.resource_mut::>(); + let mut input_events = app.world_mut().resource_mut::>(); input_events.send(TEST_PRESS); app.update(); - let input = app.world.resource::>(); + let input = app.world().resource::>(); // Input is pressed because we just sent a real event assert!(input.pressed(TEST_PRESS.key_code)); app.update(); - let input = app.world.resource::>(); + let input = app.world().resource::>(); // Input is not pressed, as playback is not enabled and the previous event expired assert!(input.pressed(TEST_PRESS.key_code)); @@ -114,7 +118,7 @@ fn capture_and_playback() { app.update(); - let input = app.world.resource::>(); + let input = app.world().resource::>(); // Input is now pressed, as the pressed key has been played back. assert!(input.pressed(TEST_PRESS.key_code)); } @@ -123,64 +127,67 @@ fn capture_and_playback() { fn repeated_playback() { // Play all of the events each pass let mut app = playback_app(PlaybackStrategy::default()); - let input_events = app.world.resource::>(); + app.world_mut() + .insert_resource(TimeUpdateStrategy::ManualDuration(Duration::from_secs(1))); + + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 0); - *app.world.resource_mut::() = simple_timestamped_input(); + *app.world_mut().resource_mut::() = simple_timestamped_input(); for _ in 1..10 { app.update(); } // Verify that we're out of events - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 0); // Reset our tracking - let mut timestamped_input: Mut = app.world.resource_mut(); + let mut timestamped_input: Mut = app.world_mut().resource_mut(); timestamped_input.reset_cursor(); // Play the events again app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 2); } #[test] fn playback_strategy_paused() { let mut app = playback_app(PlaybackStrategy::Paused); - *app.world.resource_mut::() = complex_timestamped_input(); + *app.world_mut().resource_mut::() = complex_timestamped_input(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 0); for _ in 0..10 { app.update(); } - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 0); } #[test] fn playback_strategy_frame() { let mut app = playback_app(PlaybackStrategy::FrameCount); - *app.world.resource_mut::() = complex_timestamped_input(); + *app.world_mut().resource_mut::() = complex_timestamped_input(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 0); // Check complex_timestamped_input to verify the pattern app.update(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 2); app.update(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 4); app.update(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 5); } @@ -188,9 +195,9 @@ fn playback_strategy_frame() { fn playback_strategy_frame_range_once() { let strategy = PlaybackStrategy::FrameRangeOnce(FrameCount(2), FrameCount(5)); let mut app = playback_app(strategy); - *app.world.resource_mut::() = complex_timestamped_input(); + *app.world_mut().resource_mut::() = complex_timestamped_input(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 0); // Replays the events in the frame range [2, 5) @@ -198,26 +205,27 @@ fn playback_strategy_frame_range_once() { // Then swaps to PlaybackStrategy::Paused // Frame 2 app.update(); - let input_events = app.world.resource::>(); + + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 2); // Frame 3 (events are double buffered) app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 3); // Frame 4 (events are double buffered) app.update(); - let input_events = app.world.resource::>(); - assert_eq!(*app.world.resource::(), strategy); + let input_events = app.world().resource::>(); + assert_eq!(*app.world().resource::(), strategy); assert_eq!(input_events.len(), 1); // Paused app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 0); assert_eq!( - *app.world.resource::(), + *app.world().resource::(), PlaybackStrategy::Paused ); } @@ -226,9 +234,9 @@ fn playback_strategy_frame_range_once() { fn playback_strategy_frame_range_loop() { let strategy = PlaybackStrategy::FrameRangeLoop(FrameCount(2), FrameCount(5)); let mut app = playback_app(strategy); - *app.world.resource_mut::() = complex_timestamped_input(); + *app.world_mut().resource_mut::() = complex_timestamped_input(); - let timestamped_input = app.world.resource::(); + let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 0); // Replays the events in the frame range [2, 5) @@ -236,18 +244,18 @@ fn playback_strategy_frame_range_loop() { // Then swaps to PlaybackStrategy::Paused // Frame 2 app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 2); // Frame 3 (events are double buffered) app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 3); // Frame 4 (events are double buffered) app.update(); - let input_events = app.world.resource::>(); - assert_eq!(*app.world.resource::(), strategy); + let input_events = app.world().resource::>(); + assert_eq!(*app.world().resource::(), strategy); assert_eq!(input_events.len(), 1); // Spacing frame @@ -255,10 +263,10 @@ fn playback_strategy_frame_range_loop() { // Looping back to frame 2 app.update(); - let input_events = app.world.resource::>(); + let input_events = app.world().resource::>(); assert_eq!(input_events.len(), 2); assert_eq!( - *app.world.resource::(), + *app.world().resource::(), PlaybackStrategy::FrameRangeLoop(FrameCount(2), FrameCount(5)) ); }