From a225b5b86440fd85fb2a2b754285cc379dc90244 Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Thu, 22 Aug 2024 16:27:16 -0400 Subject: [PATCH 1/2] Remove FrameCount in favor of bevy counterpart --- src/frame_counting.rs | 44 ---------------------------------------- src/input_capture.rs | 13 ++++-------- src/input_playback.rs | 19 ++++++++--------- src/lib.rs | 1 - src/timestamped_input.rs | 3 +-- tests/input_capture.rs | 8 +++----- tests/input_playback.rs | 10 ++++++--- 7 files changed, 23 insertions(+), 75 deletions(-) delete mode 100644 src/frame_counting.rs diff --git a/src/frame_counting.rs b/src/frame_counting.rs deleted file mode 100644 index ccc9056..0000000 --- a/src/frame_counting.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Counts (and updates) the frame of the app - -use bevy::ecs::prelude::*; -use serde::{Deserialize, Serialize}; -use std::ops::{Add, Sub}; -/// The number of frames that have elapsed since the app started -/// -/// Updated in [`time_tracker`] during the [`First`] schedule. -#[derive( - Resource, - Clone, - Copy, - Debug, - Default, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, -)] -pub struct FrameCount(pub u64); - -impl Add for FrameCount { - type Output = FrameCount; - fn add(self, rhs: FrameCount) -> Self::Output { - FrameCount(self.0.saturating_add(rhs.0)) - } -} - -impl Sub for FrameCount { - type Output = FrameCount; - fn sub(self, rhs: FrameCount) -> Self::Output { - FrameCount(self.0.saturating_sub(rhs.0)) - } -} - -/// A system which increases the value of the [`FrameCount`] resource by 1 every frame -/// -/// This system should run during the [`First`] schedule. -pub fn frame_counter(mut frame_count: ResMut) { - frame_count.0 += 1; -} diff --git a/src/input_capture.rs b/src/input_capture.rs index 722431b..673cd21 100644 --- a/src/input_capture.rs +++ b/src/input_capture.rs @@ -2,7 +2,8 @@ //! //! These are unified into a single [`TimestampedInputs`](crate::timestamped_input::TimestampedInputs) resource, which can be played back. -use bevy::app::{App, AppExit, First, Last, Plugin}; +use bevy::app::{App, AppExit, Last, Plugin}; +use bevy::core::{update_frame_count, FrameCount}; use bevy::ecs::prelude::*; use bevy::input::gamepad::GamepadEvent; use bevy::input::keyboard::KeyboardInput; @@ -11,7 +12,6 @@ use bevy::time::Time; use bevy::window::CursorMoved; use ron::ser::PrettyConfig; -use crate::frame_counting::{frame_counter, FrameCount}; use crate::serde::PlaybackFilePath; use crate::timestamped_input::TimestampedInputs; use std::fs::OpenOptions; @@ -27,12 +27,6 @@ pub struct InputCapturePlugin; impl Plugin for InputCapturePlugin { fn build(&self, app: &mut App) { - // Avoid double-adding frame_counter - if !app.world().contains_resource::() { - app.init_resource::() - .add_systems(First, frame_counter); - } - app.init_resource::() .init_resource::() .init_resource::() @@ -43,7 +37,8 @@ impl Plugin for InputCapturePlugin { capture_input, serialize_captured_input_on_exit, ) - .chain(), + .chain() + .before(update_frame_count), ); } } diff --git a/src/input_playback.rs b/src/input_playback.rs index 3aaef11..6f646d5 100644 --- a/src/input_playback.rs +++ b/src/input_playback.rs @@ -3,6 +3,7 @@ //! These are played back by emulating assorted Bevy input events. use bevy::app::{App, AppExit, First, Plugin, Startup}; +use bevy::core::FrameCount; use bevy::ecs::{prelude::*, system::SystemParam}; use bevy::input::gamepad::GamepadEvent; use bevy::input::{ @@ -16,7 +17,6 @@ use bevy::window::{CursorMoved, Window}; use ron::de::from_reader; use std::fs::File; -use crate::frame_counting::{frame_counter, FrameCount}; use crate::serde::PlaybackFilePath; use crate::timestamped_input::{TimestampedInputEvent, TimestampedInputs}; @@ -30,18 +30,15 @@ pub struct InputPlaybackPlugin; impl Plugin for InputPlaybackPlugin { fn build(&self, app: &mut App) { - // Avoid double-adding frame_counter - if !app.world().contains_resource::() { - app.init_resource::() - .add_systems(First, frame_counter.after(bevy::ecs::event::EventUpdates)); - } - app.init_resource::() .init_resource::() .init_resource::() .init_resource::() .add_systems(Startup, deserialize_timestamped_inputs) - .add_systems(First, playback_timestamped_input.after(frame_counter)); + .add_systems( + First, + playback_timestamped_input.after(bevy::ecs::event::EventUpdates), + ); } } @@ -249,7 +246,7 @@ impl PlaybackProgress { /// /// Panics if `self.initial_frame` is `None`. Make sure to call `set_initial_frame` first! pub fn current_frame(&self, start: FrameCount) -> FrameCount { - start + self.elapsed_frames + FrameCount(start.0.wrapping_add(self.elapsed_frames.0)) } /// Gets the current time. @@ -265,7 +262,7 @@ impl PlaybackProgress { /// /// This also records that one frame has elapsed. pub fn next_frame(&mut self, start: FrameCount) -> FrameCount { - self.elapsed_frames = self.elapsed_frames + FrameCount(1); + self.elapsed_frames = FrameCount(self.elapsed_frames.0.wrapping_add(1)); // The frame count has been advanced, so this returns the correct value self.current_frame(start) } @@ -315,7 +312,7 @@ mod tests { let delta = FrameCount(1); let next_frame = progress.next_frame(start); - assert_eq!(next_frame, start + delta); + assert_eq!(next_frame.0, start.0.wrapping_add(delta.0)); assert_eq!(progress.elapsed_frames, delta); } } diff --git a/src/lib.rs b/src/lib.rs index e64a639..9f6f6bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #![warn(clippy::doc_markdown)] #![doc = include_str!("../README.md")] -pub mod frame_counting; pub mod input_capture; pub mod input_playback; pub mod serde; diff --git a/src/timestamped_input.rs b/src/timestamped_input.rs index a6fdd12..a9c514a 100644 --- a/src/timestamped_input.rs +++ b/src/timestamped_input.rs @@ -3,6 +3,7 @@ //! Those timestamped events are finally stored inside of a [`TimestampedInputs`] resource, which should be used for input capture and playback. use bevy::app::AppExit; +use bevy::core::FrameCount; use bevy::ecs::prelude::*; use bevy::input::gamepad::GamepadEvent; use bevy::input::keyboard::KeyboardInput; @@ -11,8 +12,6 @@ use bevy::utils::Duration; use bevy::window::CursorMoved; use serde::{Deserialize, Serialize}; -use crate::frame_counting::FrameCount; - /// A timestamped device-agnostic user-input event /// /// These are re-emitted as events, and commonly serialized to disk diff --git a/tests/input_capture.rs b/tests/input_capture.rs index 3583511..415f30b 100644 --- a/tests/input_capture.rs +++ b/tests/input_capture.rs @@ -1,3 +1,4 @@ +use bevy::core::FrameCount; use bevy::input::keyboard::Key; use bevy::input::keyboard::KeyboardInput; use bevy::input::mouse::MouseButtonInput; @@ -6,7 +7,6 @@ use bevy::input::InputPlugin; use bevy::prelude::*; use bevy::window::WindowPlugin; -use leafwing_input_playback::frame_counting::FrameCount; use leafwing_input_playback::input_capture::{InputCapturePlugin, InputModesCaptured}; use leafwing_input_playback::timestamped_input::{ InputEvent, TimestampedInputEvent, TimestampedInputs, @@ -105,10 +105,8 @@ fn framecount_of_sent_events() { let first_event: TimestampedInputEvent = iterator.next().expect("Keyboard event failed."); let second_event: TimestampedInputEvent = iterator.next().expect("Mouse event failed."); - // The frame count is recorded based on the frame it is read, - // which counts up immediately - assert_eq!(first_event.frame, FrameCount(1)); - assert_eq!(second_event.frame, FrameCount(2)); + assert_eq!(first_event.frame, FrameCount(0)); + assert_eq!(second_event.frame, FrameCount(1)); } #[test] diff --git a/tests/input_playback.rs b/tests/input_playback.rs index 4417992..77d3c51 100644 --- a/tests/input_playback.rs +++ b/tests/input_playback.rs @@ -1,5 +1,6 @@ // BLOCKED: add time strategy tests: https://github.com/bevyengine/bevy/issues/6146 +use bevy::core::FrameCount; use bevy::ecs::event::EventRegistry; use bevy::input::keyboard::Key; use bevy::input::keyboard::KeyboardInput; @@ -10,7 +11,6 @@ use bevy::time::TimeUpdateStrategy; use bevy::utils::Duration; use bevy::window::WindowPlugin; -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; @@ -51,8 +51,8 @@ fn playback_app(strategy: PlaybackStrategy) -> App { fn simple_timestamped_input() -> TimestampedInputs { let mut inputs = TimestampedInputs::default(); - inputs.send(FrameCount(1), Duration::from_secs(0), TEST_PRESS.into()); - inputs.send(FrameCount(2), Duration::from_secs(0), TEST_RELEASE.into()); + inputs.send(FrameCount(0), Duration::from_secs(0), TEST_PRESS.into()); + inputs.send(FrameCount(1), Duration::from_secs(0), TEST_RELEASE.into()); inputs } @@ -178,6 +178,10 @@ fn playback_strategy_frame() { assert_eq!(timestamped_input.cursor, 0); // Check complex_timestamped_input to verify the pattern + app.update(); + let timestamped_input = app.world().resource::(); + assert_eq!(timestamped_input.cursor, 1); + app.update(); let timestamped_input = app.world().resource::(); assert_eq!(timestamped_input.cursor, 2); From bdffac8b890bc75d89d65350cad90dfa04fe742e Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Thu, 22 Aug 2024 19:04:55 -0400 Subject: [PATCH 2/2] draft release notes for this change --- RELEASES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index c59c0fc..935e690 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,10 @@ # Release Notes +## Version 0.6 (Draft) + +- migrated to Bevy 0.14 +- replaced `FrameCount` with its Bevy counterpart and updated system scheduling constraints to match the new `FrameCount`'s behavior, which updates in `Last` rather than `First` + ## Version 0.5 - migrated to Bevy 0.13