diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8957402..86db61e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,9 +27,7 @@ jobs: sweep-cache: true - name: Run tests run: | - cargo test --locked --workspace --all-features --all-targets - # Workaround for https://github.com/rust-lang/cargo/issues/6669 - cargo test --locked --workspace --all-features --doc + cargo test --locked --workspace --no-default-features # Run clippy lints. clippy: name: Clippy diff --git a/Cargo.lock b/Cargo.lock index efe3c3f..80fa240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2299,6 +2299,21 @@ dependencies = [ "libc", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -2306,6 +2321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -2314,6 +2330,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -2333,6 +2360,53 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "fuzzy-matcher" version = "0.3.7" @@ -2571,6 +2645,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -2595,11 +2675,14 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "hexlab" -version = "0.3.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b912e78d292803bc279aec3a4e2a0cdd0e0ac1540bcdc5d0f32cbfe9e4d234dc" +checksum = "7bd7c21f4e2c11d40473d1ae673905f4deae3b12104fa6d70eeef9ef385aceb6" dependencies = [ "bevy", + "bevy_reflect", + "bevy_utils", + "glam", "hexx", "rand", "thiserror 2.0.6", @@ -3083,7 +3166,7 @@ dependencies = [ [[package]] name = "maze-ascension" -version = "0.2.2" +version = "0.3.0" dependencies = [ "anyhow", "bevy", @@ -3093,6 +3176,10 @@ dependencies = [ "hexx", "log", "rand", + "rstest", + "rstest_reuse", + "strum", + "test-log", "thiserror 2.0.6", "tracing", ] @@ -3749,6 +3836,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "piper" version = "0.2.4" @@ -4032,6 +4125,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -4067,12 +4166,62 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rstest_reuse" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" +dependencies = [ + "quote", + "rand", + "syn", +] + [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.42" @@ -4086,6 +4235,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "rustybuzz" version = "0.14.1" @@ -4158,6 +4313,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + [[package]] name = "send_wrapper" version = "0.6.0" @@ -4318,6 +4479,28 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "svg_fmt" version = "0.4.4" @@ -4401,6 +4584,27 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-log" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +dependencies = [ + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thiserror" version = "1.0.69" diff --git a/Cargo.toml b/Cargo.toml index ed2c0c4..51fdb63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "maze-ascension" authors = ["Kristofers Solo "] -version = "0.2.2" +version = "0.3.0" edition = "2021" [dependencies] @@ -18,12 +18,19 @@ tracing = { version = "0.1", features = [ "release_max_level_warn", ] } hexx = { version = "0.19", features = ["bevy_reflect", "grid"] } -hexlab = { version = "0.3", features = ["bevy"] } +hexlab = { version = "0.5", features = ["bevy"] } bevy-inspector-egui = { version = "0.28", optional = true } bevy_egui = { version = "0.31", optional = true } thiserror = "2.0" anyhow = "1" +strum = { version = "0.26", features = ["derive"] } +[dev-dependencies] +rstest = "0.23" +rstest_reuse = "0.7" +test-log = { version = "0.2.16", default-features = false, features = [ + "trace", +] } [features] default = [ @@ -54,6 +61,8 @@ dev_native = [ too_many_arguments = "allow" # Queries that access many components may trigger this lint. type_complexity = "allow" +nursery = { level = "warn", priority = -1 } +unwrap_used = "warn" # Compile with Performance Optimizations: diff --git a/justfile b/justfile index 56e184f..2d1d43f 100644 --- a/justfile +++ b/justfile @@ -17,4 +17,3 @@ web-dev: # Run web release web-release: trunk serve --release --no-default-features - diff --git a/src/asset_tracking.rs b/src/asset_tracking.rs index f61992a..396ab1f 100644 --- a/src/asset_tracking.rs +++ b/src/asset_tracking.rs @@ -1,8 +1,7 @@ //! A high-level way to load collections of asset handles as resources. -use std::collections::VecDeque; - use bevy::prelude::*; +use std::collections::VecDeque; pub(super) fn plugin(app: &mut App) { app.init_resource::(); @@ -51,7 +50,9 @@ fn load_resource_assets(world: &mut World) { world.resource_scope(|world, mut resource_handles: Mut| { world.resource_scope(|world, assets: Mut| { for _ in 0..resource_handles.waiting.len() { - let (handle, insert_fn) = resource_handles.waiting.pop_front().unwrap(); + let Some((handle, insert_fn)) = resource_handles.waiting.pop_front() else { + continue; + }; if assets.is_loaded_with_dependencies(&handle) { insert_fn(world, &handle); resource_handles.finished.push(handle); diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..5e5fb5b --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,3 @@ +pub const MOVEMENT_THRESHOLD: f32 = 0.01; +pub const WALL_OVERLAP_MODIFIER: f32 = 1.25; +pub const FLOOR_Y_OFFSET: u8 = 100; diff --git a/src/dev_tools/ui/maze_controls.rs b/src/dev_tools/ui/maze_controls.rs index 95002cb..6c94755 100644 --- a/src/dev_tools/ui/maze_controls.rs +++ b/src/dev_tools/ui/maze_controls.rs @@ -12,7 +12,7 @@ use hexx::{Hex, HexOrientation}; use rand::{thread_rng, Rng}; use std::ops::RangeInclusive; -pub(crate) fn maze_controls_ui(world: &mut World) { +pub fn maze_controls_ui(world: &mut World) { if world.get_resource::().is_none() { return; } diff --git a/src/dev_tools/ui/mod.rs b/src/dev_tools/ui/mod.rs index 63c404f..4923190 100644 --- a/src/dev_tools/ui/mod.rs +++ b/src/dev_tools/ui/mod.rs @@ -1,3 +1,3 @@ mod maze_controls; -pub(crate) use maze_controls::maze_controls_ui; +pub use maze_controls::maze_controls_ui; diff --git a/src/floor/components.rs b/src/floor/components.rs index de73815..65ab700 100644 --- a/src/floor/components.rs +++ b/src/floor/components.rs @@ -1,19 +1,59 @@ use bevy::prelude::*; -#[derive(Debug, Reflect, Component)] +#[derive(Debug, Reflect, Component, Deref, DerefMut)] #[reflect(Component)] pub struct Floor(pub u8); #[derive(Debug, Reflect, Component)] #[reflect(Component)] -pub struct TargetFloor(pub u8); +pub struct CurrentFloor; #[derive(Debug, Reflect, Component)] #[reflect(Component)] -pub struct CurrentFloor; +pub struct NextFloor; + +#[derive(Debug, Reflect, Component, Deref, DerefMut)] +#[reflect(Component)] +pub struct FloorYTarget(pub f32); impl Default for Floor { fn default() -> Self { Self(1) } } + +impl Floor { + pub const fn increased(&self) -> Self { + Self(self.0.saturating_add(1)) + } + + pub fn decreased(&self) -> Self { + Self(self.0.saturating_sub(1).max(1)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::rstest; + + #[rstest] + #[case(0, 1)] + #[case(1, 2)] + #[case(254, 255)] + #[case(255, 255)] + fn increase(#[case] input: u8, #[case] expected: u8) { + let floor = Floor(input); + assert_eq!(*floor.increased(), expected); + } + + #[rstest] + #[case(0, 1)] // clamps to 1 + #[case(1, 1)] // clamps to 1 + #[case(2, 1)] + #[case(255, 254)] + fn decrease(#[case] input: u8, #[case] expected: u8) { + let floor = Floor(input); + assert_eq!(*floor.decreased(), expected); + } +} diff --git a/src/floor/events.rs b/src/floor/events.rs index d9bd31c..11b79ab 100644 --- a/src/floor/events.rs +++ b/src/floor/events.rs @@ -1,20 +1,45 @@ use bevy::prelude::*; -use crate::maze::components::MazeConfig; +use super::components::Floor; -#[derive(Debug, Reflect, Event)] -pub struct SpawnFloor { - pub floor: u8, - pub config: MazeConfig, +#[derive(Debug, Clone, Copy, Reflect, Event, Default, PartialEq, Eq)] +pub enum TransitionFloor { + #[default] + Ascend, + Descend, } -#[derive(Debug, Reflect, Event)] -pub struct RespawnFloor { - pub floor: u8, - pub config: MazeConfig, +impl TransitionFloor { + pub fn into_direction(&self) -> f32 { + self.into() + } + + pub const fn opposite(&self) -> Self { + match self { + Self::Ascend => Self::Descend, + Self::Descend => Self::Ascend, + } + } + + pub fn next_floor_num(&self, floor: &Floor) -> u8 { + match self { + Self::Ascend => *floor.increased(), + Self::Descend => *floor.decreased(), + } + } } -#[derive(Debug, Reflect, Event)] -pub struct DespawnFloor { - pub floor: u8, +impl From for f32 { + fn from(value: TransitionFloor) -> Self { + Self::from(&value) + } +} + +impl From<&TransitionFloor> for f32 { + fn from(value: &TransitionFloor) -> Self { + match value { + TransitionFloor::Ascend => -1., + TransitionFloor::Descend => 1., + } + } } diff --git a/src/floor/mod.rs b/src/floor/mod.rs index b071bcf..7cb7527 100644 --- a/src/floor/mod.rs +++ b/src/floor/mod.rs @@ -1,7 +1,14 @@ pub mod components; pub mod events; +pub mod resources; mod systems; use bevy::prelude::*; +use events::TransitionFloor; +use resources::HighestFloor; -pub(super) fn plugin(_app: &mut App) {} +pub(super) fn plugin(app: &mut App) { + app.add_event::() + .insert_resource(HighestFloor(1)) + .add_plugins(systems::plugin); +} diff --git a/src/floor/resources.rs b/src/floor/resources.rs new file mode 100644 index 0000000..80e447c --- /dev/null +++ b/src/floor/resources.rs @@ -0,0 +1,5 @@ +use bevy::prelude::*; + +#[derive(Debug, Default, Reflect, Resource, PartialEq, Eq)] +#[reflect(Resource)] +pub struct HighestFloor(pub u8); diff --git a/src/floor/systems/clear_events.rs b/src/floor/systems/clear_events.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/floor/systems/despawn.rs b/src/floor/systems/despawn.rs new file mode 100644 index 0000000..3567c3b --- /dev/null +++ b/src/floor/systems/despawn.rs @@ -0,0 +1,3 @@ +use bevy::prelude::*; + +pub const fn despawn_floor(mut _commands: Commands) {} diff --git a/src/floor/systems/mod.rs b/src/floor/systems/mod.rs index 8b13789..2d424d4 100644 --- a/src/floor/systems/mod.rs +++ b/src/floor/systems/mod.rs @@ -1 +1,23 @@ +mod clear_events; +mod despawn; +mod movement; +mod spawn; +use crate::maze::MazePluginLoaded; +use bevy::prelude::*; +use despawn::despawn_floor; +use movement::{handle_floor_transition_events, move_floors}; +use spawn::spawn_floor; + +pub(super) fn plugin(app: &mut App) { + app.add_systems( + Update, + ( + spawn_floor, + despawn_floor, + handle_floor_transition_events, + move_floors.after(handle_floor_transition_events), + ) + .run_if(resource_exists::), + ); +} diff --git a/src/floor/systems/movement.rs b/src/floor/systems/movement.rs new file mode 100644 index 0000000..ec8ce20 --- /dev/null +++ b/src/floor/systems/movement.rs @@ -0,0 +1,79 @@ +use crate::{ + constants::{FLOOR_Y_OFFSET, MOVEMENT_THRESHOLD}, + floor::{ + components::{CurrentFloor, FloorYTarget, NextFloor}, + events::TransitionFloor, + }, + maze::components::HexMaze, + player::components::{MovementSpeed, Player}, +}; + +use bevy::prelude::*; + +pub fn move_floors( + mut commands: Commands, + mut maze_query: Query< + (Entity, &mut Transform, &FloorYTarget), + (With, With), + >, + player_query: Query<&MovementSpeed, With>, + time: Res