From 44ff1f32defd5dfb0576af20a0e48971cb1058b0 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Wed, 9 Apr 2025 23:09:19 -0700 Subject: [PATCH] Bevy 0.16 (#46) # Objective - Working branch to target all fixes for bevy 0.16 Co-authored-by: Zachary Harrold --- .github/workflows/rust.yml | 12 +- CHANGELOG.md | 7 +- Cargo.toml | 127 +++++++++++---- README.md | 12 +- benches/benchmarks.rs | 30 ++-- examples/debug.rs | 17 +- examples/demo.rs | 47 +++--- examples/error.rs | 25 +-- examples/error_child.rs | 11 +- examples/infinite.rs | 11 +- examples/minimal.rs | 6 +- examples/{particles.rs => particles.rs.todo} | 0 examples/planets.rs | 41 +++-- examples/small_scale.rs | 21 ++- examples/spatial_hash.rs | 135 +++++++--------- examples/split_screen.rs | 32 ++-- src/bundles.rs | 2 +- src/camera.rs | 10 +- src/commands.rs | 22 ++- src/debug.rs | 10 +- src/floating_origins.rs | 15 +- src/grid/cell.rs | 43 +++-- src/grid/local_origin.rs | 47 +++--- src/grid/mod.rs | 24 ++- src/grid/propagation.rs | 103 ++++++------ src/hash/component.rs | 38 +++-- src/hash/map.rs | 33 ++-- src/hash/mod.rs | 9 +- src/hash/partition.rs | 71 ++++----- src/lib.rs | 16 +- src/plugin.rs | 159 ++++++++++++++++++- src/portable_par.rs | 126 +++++++++++++++ src/timing.rs | 11 +- src/validation.rs | 39 +++-- src/world_query.rs | 4 +- 35 files changed, 861 insertions(+), 455 deletions(-) rename examples/{particles.rs => particles.rs.todo} (100%) create mode 100644 src/portable_par.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 98cf899..de1166d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - - run: cargo check --features=all --all-targets + - run: cargo check --all-features --all-targets check-no-defaults: runs-on: ubuntu-latest @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - - run: cargo check --no-default-features --all-targets + - run: cargo check --no-default-features --all-targets --features=libm clippy: runs-on: ubuntu-latest @@ -48,7 +48,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - run: rustup component add clippy - - run: cargo clippy --features=all --all-targets -- -D warnings + - run: cargo clippy --all-features --all-targets -- -D warnings doc: runs-on: ubuntu-latest @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - - run: cargo doc --features=all --no-deps + - run: cargo doc --all-features --no-deps env: RUSTDOCFLAGS: -D warnings @@ -68,7 +68,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - - run: cargo test --features=all + - run: cargo test --all-features doctest: runs-on: ubuntu-latest @@ -77,4 +77,4 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.7.0 - - run: cargo test --features=all --doc \ No newline at end of file + - run: cargo test --all-features --doc \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e07bb1..117f5da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## UNRELEASED +### New: `no_std` Support + +Thanks to `bushrat011899`'s efforts upstream and in this crate, it is now possible to use the plugin without the rust standard library. This is particularly useful when targeting embedded or console targets. + +## v0.9.0 - 2024-12-23 + ### New: `GridCell` Spatial Hashing Spatial hashing makes fast spatial queries and neighbor lookups possible. This release adds the `GridHashMap`, an automatically updated map of the entities in each grid cell. This makes it possible to query things like: @@ -37,5 +43,4 @@ The newly added types follow this pattern: - `GridPartition`: Group of adjacent grid cells. - `GridPartitionMap`: A map for finding independent partitions of entities. - It should now be more clear how all of the `Grid` types are related to each other. \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 2a6ed68..abd7483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,42 +9,57 @@ repository = "https://github.com/aevyrie/big_space" documentation = "https://docs.rs/crate/big_space/latest" [features] -default = [] -all = ["debug", "camera"] # Can't use all-features, integer type features are incompatible. -debug = ["bevy_gizmos", "bevy_color"] -camera = ["bevy_render", "bevy_time", "bevy_input"] +default = ["std"] +debug = ["std", "bevy_gizmos", "bevy_color"] +camera = ["std", "bevy_render", "bevy_time", "bevy_input"] i8 = [] i16 = [] i32 = [] i64 = [] i128 = [] -[dependencies] -tracing = "0.1" # Less deps than pulling in bevy_log -smallvec = "1.13.2" # Already used by bevy in commands -bevy_app = { version = "0.15.0", default-features = false } -bevy_ecs = { version = "0.15.0", default-features = true } -bevy_hierarchy = { version = "0.15.0", default-features = false } -bevy_math = { version = "0.15.0", default-features = false } -bevy_reflect = { version = "0.15.0", default-features = false } -bevy_tasks = { version = "0.15.0", default-features = false } -bevy_transform = { version = "0.15.0", default-features = false, features = [ - "bevy-support", -] } -bevy_utils = { version = "0.15.0", default-features = false } -# Optional -bevy_color = { version = "0.15.0", default-features = false, optional = true } -bevy_gizmos = { version = "0.15.0", default-features = false, optional = true } -bevy_render = { version = "0.15.0", default-features = false, optional = true } -bevy_input = { version = "0.15.0", default-features = false, optional = true } -bevy_time = { version = "0.15.0", default-features = false, optional = true } +std = [ + "bevy_app/std", + "bevy_ecs/std", + "bevy_math/std", + "bevy_reflect/std", + "bevy_tasks/std", + "bevy_transform/std", + "bevy_utils/std", + "bevy_platform_support/std", + "bevy_color?/std", + "bevy_input?/std", + "bevy_time?/std", +] +libm = ["bevy_math/libm", "dep:libm"] +[dependencies] +tracing = { version = "0.1", default-features = false } # Less deps than pulling in bevy_log +smallvec = { version = "1.13.2", default-features = false } # Already used by bevy in commands +bevy_app = { version = "0.16.0-rc.3", default-features = false, features = ["bevy_reflect"] } +bevy_ecs = { version = "0.16.0-rc.3", default-features = false } +bevy_math = { version = "0.16.0-rc.3", default-features = false } +bevy_reflect = { version = "0.16.0-rc.3", default-features = false, features = ["glam"] } +bevy_tasks = { version = "0.16.0-rc.3", default-features = false } +bevy_transform = { version = "0.16.0-rc.3", default-features = false, features = [ + "bevy-support", + "bevy_reflect", +] } +bevy_utils = { version = "0.16.0-rc.3", default-features = false } +bevy_platform_support = { version = "0.16.0-rc.3", default-features = false, features = ["alloc"] } +# Optional +bevy_color = { version = "0.16.0-rc.3", default-features = false, optional = true } +bevy_gizmos = { version = "0.16.0-rc.3", default-features = false, optional = true } +bevy_render = { version = "0.16.0-rc.3", default-features = false, optional = true } +bevy_input = { version = "0.16.0-rc.3", default-features = false, optional = true } +bevy_time = { version = "0.16.0-rc.3", default-features = false, optional = true } +libm = { version = "0.2", default-features = false, optional = true } [dev-dependencies] -big_space = { path = "", features = ["debug", "camera"] } -bevy = { version = "0.15.0", default-features = false, features = [ +bevy = { version = "0.16.0-rc.3", default-features = false, features = [ "bevy_scene", "bevy_asset", + "bevy_color", "bevy_gltf", "bevy_winit", "default_font", @@ -61,7 +76,36 @@ noise = "0.9" turborand = "0.10" criterion = "0.5" bytemuck = "1.20" -bevy_hanabi = "0.14" +# bevy_hanabi = "0.14" # TODO: Update + +[lints.clippy] +doc_markdown = "warn" +manual_let_else = "warn" +match_same_arms = "warn" +redundant_closure_for_method_calls = "warn" +redundant_else = "warn" +semicolon_if_nothing_returned = "warn" +type_complexity = "allow" +undocumented_unsafe_blocks = "warn" +unwrap_or_default = "warn" + +ptr_as_ptr = "warn" +ptr_cast_constness = "warn" +ref_as_ptr = "warn" + +# see: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366966219 +too_long_first_doc_paragraph = "allow" + +std_instead_of_core = "warn" +std_instead_of_alloc = "warn" +alloc_instead_of_core = "warn" + +[lints.rust] +missing_docs = "warn" +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] } +unsafe_code = "deny" +unsafe_op_in_unsafe_fn = "warn" +unused_qualifications = "warn" [[bench]] name = "benchmarks" @@ -70,18 +114,19 @@ harness = false [[example]] name = "debug" path = "examples/debug.rs" +required-features = ["debug"] doc-scrape-examples = false [[example]] name = "demo" path = "examples/demo.rs" -required-features = ["i128"] +required-features = ["i128", "camera", "debug"] doc-scrape-examples = false - [[example]] name = "error_child" path = "examples/error_child.rs" +required-features = ["camera", "debug"] doc-scrape-examples = false [[example]] @@ -92,25 +137,41 @@ doc-scrape-examples = false [[example]] name = "infinite" path = "examples/infinite.rs" -required-features = ["i8"] +required-features = ["i8", "camera", "debug"] doc-scrape-examples = false [[example]] name = "minimal" path = "examples/minimal.rs" +required-features = ["camera"] doc-scrape-examples = false -[[example]] -name = "particles" -path = "examples/particles.rs" -doc-scrape-examples = false +# TODO: Uncomment once bevy_hanabi is updated +# [[example]] +# name = "particles" +# path = "examples/particles.rs" +# doc-scrape-examples = false [[example]] name = "planets" path = "examples/planets.rs" +required-features = ["camera"] +doc-scrape-examples = false + +[[example]] +name = "small_scale" +path = "examples/small_scale.rs" +required-features = ["camera", "debug"] +doc-scrape-examples = false + +[[example]] +name = "spatial_hash" +path = "examples/spatial_hash.rs" +required-features = ["camera"] doc-scrape-examples = false [[example]] name = "split_screen" path = "examples/split_screen.rs" +required-features = ["camera", "debug"] doc-scrape-examples = false diff --git a/README.md b/README.md index 25fe398..e804efc 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Huge worlds, high performance, no dependencies, ecosystem compatibility. [Read the docs](https://docs.rs/big_space) - + [![crates.io](https://img.shields.io/crates/v/big_space)](https://crates.io/crates/big_space) [![docs.rs](https://docs.rs/big_space/badge.svg)](https://docs.rs/big_space) [![test suite](https://github.com/aevyrie/big_space/actions/workflows/rust.yml/badge.svg)](https://github.com/aevyrie/big_space/actions/workflows/rust.yml) @@ -18,11 +18,10 @@ Huge worlds, high performance, no dependencies, ecosystem compatibility. [Read t - Uses `Transform`, making it compatible with most of the Bevy ecosystem. - No added dependencies. - Absolute coordinates without drift, unlike camera-relative or periodic recentering solutions. -- Chunks the world into integer grids, from `i8` up to `i128`. -- Grids can be nested. +- Chunks the world into nestable integer grids, from `i8` up to `i128`. - Spatial hashing for fast grid cell lookups and neighbor search. -- Spatial partitioning to group sets of disconnected entities. -- 3-5x faster than Bevy's transform propagation for wide hierarchies. +- Spatial partitioning to group sets of connected cells. +- Great performance scaling and parallelism with massive entity counts. - 👉 [Extensive documentation you should read.](https://docs.rs/big_space) ![screenshot](https://github.com/user-attachments/assets/736a1dec-91a1-4ac1-9382-82084ebe6c1c) @@ -40,7 +39,8 @@ https://github.com/user-attachments/assets/9ce5283f-7d48-47dc-beef-9a7626858ed4 ## Bevy Version Support | bevy | big_space | -| ---- | --------- | +|------|-----------| +| 0.16 | 0.10 | | 0.15 | 0.8, 0.9 | | 0.14 | 0.7 | | 0.13 | 0.5, 0.6 | diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs index 325fa26..24ecbc4 100644 --- a/benches/benchmarks.rs +++ b/benches/benchmarks.rs @@ -1,9 +1,11 @@ +//! `big_space` benchmarks. #![allow(clippy::type_complexity)] +#![allow(missing_docs)] use bevy::prelude::*; use big_space::prelude::*; +use core::{iter::repeat_with, ops::Neg}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use std::{iter::repeat_with, ops::Neg}; use turborand::prelude::*; criterion_group!( @@ -52,7 +54,7 @@ fn deep_hierarchy(c: &mut Criterion) { fn translate(mut transforms: Query<&mut Transform>) { transforms.iter_mut().for_each(|mut transform| { transform.translation += Vec3::ONE; - }) + }); } let mut app = App::new(); @@ -91,7 +93,7 @@ fn wide_hierarchy(c: &mut Criterion) { fn translate(mut transforms: Query<&mut Transform>) { transforms.iter_mut().for_each(|mut transform| { transform.translation += Vec3::ONE; - }) + }); } let mut app = App::new(); @@ -126,9 +128,9 @@ fn spatial_hashing(c: &mut Criterion) { let rng = Rng::with_seed(342525); let values: Vec<_> = repeat_with(|| { [ - rng.i64(-HALF_WIDTH..=HALF_WIDTH), - rng.i64(-HALF_WIDTH..=HALF_WIDTH), - rng.i64(-HALF_WIDTH..=HALF_WIDTH), + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, ] }) .take(N_SPAWN) @@ -143,7 +145,7 @@ fn spatial_hashing(c: &mut Criterion) { fn translate(mut cells: Query<&mut GridCell>) { cells.iter_mut().take(N_MOVE).for_each(|mut cell| { *cell += GridCell::ONE; - }) + }); } let mut app = App::new(); @@ -204,7 +206,7 @@ fn spatial_hashing(c: &mut Criterion) { // }); // }); - fn setup_uniform(mut commands: Commands) { + fn setup_uniform(mut commands: Commands) { commands.spawn_big_space(Grid::new(1.0, 0.0), |root| { for x in HALF_EXTENT.neg()..HALF_EXTENT { for y in HALF_EXTENT.neg()..HALF_EXTENT { @@ -226,7 +228,8 @@ fn spatial_hashing(c: &mut Criterion) { let parent = app .world_mut() .query_filtered::>() - .single(app.world()); + .single(app.world()) + .unwrap(); let spatial_map = app.world().resource::(); let hash = GridHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 }); let entry = spatial_map.get(&hash).unwrap(); @@ -254,7 +257,8 @@ fn spatial_hashing(c: &mut Criterion) { let parent = app .world_mut() .query_filtered::>() - .single(app.world()); + .single(app.world()) + .unwrap(); let spatial_map = app.world().resource::(); let hash = GridHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 }); let entry = spatial_map.get(&hash).unwrap(); @@ -288,9 +292,9 @@ fn hash_filtering(c: &mut Criterion) { let rng = Rng::with_seed(342525); let values: Vec<_> = repeat_with(|| { [ - rng.i64(-HALF_WIDTH..=HALF_WIDTH), - rng.i64(-HALF_WIDTH..=HALF_WIDTH), - rng.i64(-HALF_WIDTH..=HALF_WIDTH), + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, + rng.i64(-HALF_WIDTH..=HALF_WIDTH) as GridPrecision, ] }) .take(N_ENTITIES) diff --git a/examples/debug.rs b/examples/debug.rs index 5b06c38..98d7839 100644 --- a/examples/debug.rs +++ b/examples/debug.rs @@ -1,3 +1,4 @@ +//! Demonstrates debugging visualization for `big_space` components. #![allow(clippy::type_complexity)] use bevy::{color::palettes, prelude::*}; @@ -6,9 +7,9 @@ use big_space::prelude::*; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), - big_space::debug::FloatingOriginDebugPlugin::default(), + FloatingOriginDebugPlugin::default(), )) .add_systems(Startup, setup) .add_systems(Update, (movement, rotation)) @@ -26,7 +27,7 @@ fn movement( Query<&mut Transform, With>>, Query<&mut Transform, With>>, )>, -) { +) -> Result { let delta_translation = |offset: f32, scale: f32| -> Vec3 { let t_1 = time.elapsed_secs() * 0.1 + offset; let dt = time.delta_secs() * 0.1; @@ -38,10 +39,12 @@ fn movement( p1 - p0 }; - q.p0().single_mut().translation += delta_translation(20.0, 1.0); - q.p1().single_mut().translation += delta_translation(251.0, 1.0); - q.p2().single_mut().translation += delta_translation(812.0, 1.0); - q.p3().single_mut().translation += delta_translation(863.0, 0.4); + q.p0().single_mut()?.translation += delta_translation(20.0, 1.0); + q.p1().single_mut()?.translation += delta_translation(251.0, 1.0); + q.p2().single_mut()?.translation += delta_translation(812.0, 1.0); + q.p3().single_mut()?.translation += delta_translation(863.0, 0.4); + + Ok(()) } #[derive(Component)] diff --git a/examples/demo.rs b/examples/demo.rs index f6dbd58..802de7d 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,3 +1,5 @@ +//! Demonstrates using the plugin over a wide range of scales, from protons to the universe. + use bevy::{ color::palettes, prelude::*, @@ -13,10 +15,10 @@ use big_space::{ fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), FloatingOriginDebugPlugin::default(), - big_space::camera::CameraControllerPlugin::default(), + CameraControllerPlugin::default(), )) .insert_resource(ClearColor(Color::BLACK)) .add_systems(Startup, (setup, ui_setup)) @@ -79,10 +81,10 @@ fn setup( } #[derive(Component, Reflect)] -pub struct BigSpaceDebugText; +struct BigSpaceDebugText; #[derive(Component, Reflect)] -pub struct FunFactText; +struct FunFactText; fn ui_setup(mut commands: Commands) { commands.spawn(( @@ -125,13 +127,11 @@ fn highlight_nearest_sphere( cameras: Query<&CameraController>, objects: Query<&GlobalTransform>, mut gizmos: Gizmos, -) { - let Some((entity, _)) = cameras.single().nearest_object() else { - return; - }; - let Ok(transform) = objects.get(entity) else { - return; +) -> Result { + let Some((entity, _)) = cameras.single()?.nearest_object() else { + return Ok(()); }; + let transform = objects.get(entity)?; // Ignore rotation due to panicking in gizmos, as of bevy 0.13 let (scale, _, translation) = transform.to_scale_rotation_translation(); gizmos @@ -141,6 +141,7 @@ fn highlight_nearest_sphere( Color::Srgba(palettes::basic::RED), ) .resolution(128); + Ok(()) } #[allow(clippy::type_complexity)] @@ -155,8 +156,8 @@ fn ui_text_system( origin: Query<(Entity, GridTransformReadOnly), With>, camera: Query<&CameraController>, objects: Query<&Transform, With>, -) { - let (origin_entity, origin_pos) = origin.single(); +) -> Result { + let (origin_entity, origin_pos) = origin.single()?; let translation = origin_pos.transform.translation; let grid_text = format!( @@ -170,7 +171,7 @@ fn ui_text_system( ); let Some(grid) = grids.parent_grid(origin_entity) else { - return; + return Ok(()); }; let real_position = grid.grid_position_double(origin_pos.cell, origin_pos.transform); @@ -183,7 +184,7 @@ fn ui_text_system( real_position.x as f32, real_position.y as f32, real_position.z as f32 ); - let velocity = camera.single().velocity(); + let velocity = camera.single()?.velocity(); let speed = velocity.0.length() / time.delta_secs_f64(); let camera_text = if speed > 3.0e8 { format!("Speed: {:.0e} * speed of light", speed / 3.0e8) @@ -191,8 +192,8 @@ fn ui_text_system( format!("Speed: {:.2e} m/s", speed) }; - let (nearest_text, fact_text) = if let Some(nearest) = camera.single().nearest_object() { - let dia = objects.get(nearest.0).unwrap().scale.max_element(); + let (nearest_text, fact_text) = if let Some(nearest) = camera.single()?.nearest_object() { + let dia = objects.get(nearest.0)?.scale.max_element(); let (fact_dia, fact) = closest(dia); let dist = nearest.1; let multiple = dia / fact_dia; @@ -206,13 +207,15 @@ fn ui_text_system( ("".into(), "".into()) }; - let mut debug_text = debug_text.single_mut(); + let mut debug_text = debug_text.single_mut()?; debug_text.0.0 = format!( "{grid_text}\n{translation_text}\n\n{real_position_f64_text}\n{real_position_f32_text}\n\n{camera_text}\n{nearest_text}" ); - fun_text.single_mut().0 = fact_text + fun_text.single_mut()?.0 = fact_text; + + Ok(()) } fn closest<'a>(diameter: f32) -> (f32, &'a str) { @@ -262,10 +265,8 @@ fn cursor_grab_system( mut cam: ResMut, btn: Res>, key: Res>, -) { - let Some(mut window) = windows.get_single_mut().ok() else { - return; - }; +) -> Result { + let mut window = windows.single_mut()?; if btn.just_pressed(MouseButton::Left) { window.cursor_options.grab_mode = CursorGrabMode::Locked; @@ -280,4 +281,6 @@ fn cursor_grab_system( // window.mode = WindowMode::Windowed; cam.defaults_disabled = true; } + + Ok(()) } diff --git a/examples/error.rs b/examples/error.rs index cb08217..7a0b9fd 100644 --- a/examples/error.rs +++ b/examples/error.rs @@ -10,7 +10,10 @@ use big_space::prelude::*; fn main() { App::new() - .add_plugins((DefaultPlugins, BigSpacePlugin::default())) + .add_plugins(( + DefaultPlugins.build().disable::(), + BigSpacePlugin::default(), + )) .add_systems(Startup, (setup_scene, setup_ui)) .add_systems(Update, (rotator_system, toggle_plugin)) .run(); @@ -22,8 +25,8 @@ fn main() { /// floating point error when we disable this plugin. /// /// This plugin can function much further from the origin without any issues. Try setting this to: -/// 10_000_000_000_000_000 with the default i64 feature, or -/// 10_000_000_000_000_000_000_000_000_000_000_000_000 with the i128 feature. +/// `10_000_000_000_000_000` with the default i64 feature, or +/// `10_000_000_000_000_000_000_000_000_000_000_000_000` with the i128 feature. const DISTANCE: GridPrecision = 2_000_000; /// Move the floating origin back to the "true" origin when the user presses the spacebar to emulate @@ -35,14 +38,16 @@ fn toggle_plugin( mut text: Query<&mut Text>, mut disabled: Local, mut floating_origin: Query<(Entity, &mut GridCell), With>, -) { +) -> Result { if input.just_pressed(KeyCode::Space) { *disabled = !*disabled; } - let this_grid = grids.parent_grid(floating_origin.single().0).unwrap(); + let this_grid = grids + .parent_grid(floating_origin.single().unwrap().0) + .unwrap(); - let mut origin_cell = floating_origin.single_mut().1; + let mut origin_cell = floating_origin.single_mut()?.1; let index_max = DISTANCE / this_grid.cell_edge_length() as GridPrecision; let increment = index_max / 100; @@ -73,14 +78,16 @@ fn toggle_plugin( .as_bytes() .rchunks(3) .rev() - .map(std::str::from_utf8) + .map(core::str::from_utf8) .collect::, _>>() .unwrap() .join(",") // separator }; - text.single_mut().0 = - format!("Press Spacebar to toggle: {msg}\nCamera distance to floating origin: {}\nMesh distance from origin: {}", thousands(dist), thousands(DISTANCE)) + text.single_mut()?.0 = + format!("Press Spacebar to toggle: {msg}\nCamera distance to floating origin: {}\nMesh distance from origin: {}", thousands(dist), thousands(DISTANCE)); + + Ok(()) } #[derive(Component)] diff --git a/examples/error_child.rs b/examples/error_child.rs index 50faf9f..7546d5f 100644 --- a/examples/error_child.rs +++ b/examples/error_child.rs @@ -1,15 +1,14 @@ //! This example demonstrates error accumulating from parent to children in nested grids. -use bevy::{math::DVec3, prelude::*}; -use bevy_color::palettes; +use bevy::{color::palettes, math::DVec3, prelude::*}; use big_space::prelude::*; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), - big_space::camera::CameraControllerPlugin::default(), - big_space::debug::FloatingOriginDebugPlugin::default(), + CameraControllerPlugin::default(), + FloatingOriginDebugPlugin::default(), )) .add_systems(Startup, setup_scene) .run(); @@ -86,7 +85,7 @@ fn setup_scene( ..default() }), FloatingOrigin, - big_space::camera::CameraController::default() // Built-in camera controller + CameraController::default() // Built-in camera controller .with_speed_bounds([10e-18, 10e35]) .with_smoothness(0.9, 0.8) .with_speed(1.0), diff --git a/examples/infinite.rs b/examples/infinite.rs index ab73853..684be7a 100644 --- a/examples/infinite.rs +++ b/examples/infinite.rs @@ -1,4 +1,5 @@ -//! Big spaces are infinite, looping back on themselves smoothly. +//! Big spaces are infinite, looping back on themselves smoothly. This example requires the use of +//! the `i8` feature, because a small world is needed to be able to see the "edge". use bevy::prelude::*; use big_space::prelude::*; @@ -6,10 +7,10 @@ use big_space::prelude::*; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), - FloatingOriginDebugPlugin::default(), // Draws cell AABBs and grids - big_space::camera::CameraControllerPlugin::default(), // Compatible controller + FloatingOriginDebugPlugin::default(), + CameraControllerPlugin::default(), )) .add_systems(Startup, setup_scene) .run(); @@ -44,7 +45,7 @@ fn setup_scene( Camera3d::default(), Transform::from_xyz(0.0, 0.0, 10.0), FloatingOrigin, - big_space::camera::CameraController::default() + CameraController::default() .with_speed(10.) .with_smoothness(0.99, 0.95), )); diff --git a/examples/minimal.rs b/examples/minimal.rs index 7946bb0..a4d368d 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -10,10 +10,10 @@ const BIG_DISTANCE: f64 = 1_000_000_000_000_000_000.0; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), FloatingOriginDebugPlugin::default(), // Draws cell AABBs and grids - big_space::camera::CameraControllerPlugin::default(), // Compatible controller + CameraControllerPlugin::default(), // Compatible controller )) .add_systems(Startup, setup_scene) .run(); @@ -67,7 +67,7 @@ fn setup_scene( Transform::from_translation(cell_offset + Vec3::new(0.0, 0.0, 10.0)), grid_cell, FloatingOrigin, - big_space::camera::CameraController::default(), + CameraController::default(), )); }); } diff --git a/examples/particles.rs b/examples/particles.rs.todo similarity index 100% rename from examples/particles.rs rename to examples/particles.rs.todo diff --git a/examples/planets.rs b/examples/planets.rs index 70731e3..aa10271 100644 --- a/examples/planets.rs +++ b/examples/planets.rs @@ -1,4 +1,7 @@ -use std::collections::VecDeque; +//! A practical example of a spare ship on a planet, in a solar system, surrounded by stars. +extern crate alloc; + +use alloc::collections::VecDeque; use bevy::{ color::palettes, @@ -15,14 +18,15 @@ use turborand::{rng::Rng, TurboRand}; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::new(true), - big_space::camera::CameraControllerPlugin::default(), + CameraControllerPlugin::default(), )) .insert_resource(ClearColor(Color::BLACK)) .insert_resource(AmbientLight { color: Color::WHITE, brightness: 200.0, + ..Default::default() }) .add_systems(Startup, spawn_solar_system) .add_systems( @@ -69,11 +73,12 @@ fn rotate(mut rotate_query: Query<(&mut Transform, &Rotates)>) { fn lighting( mut light: Query<(&mut Transform, &mut GlobalTransform), With>, sun: Query<&GlobalTransform, (With, Without)>, -) { - let sun_pos = sun.single().translation(); - let (mut light_tr, mut light_gt) = light.single_mut(); +) -> Result { + let sun_pos = sun.single()?.translation(); + let (mut light_tr, mut light_gt) = light.single_mut()?; light_tr.look_at(-sun_pos, Vec3::Y); *light_gt = (*light_tr).into(); + Ok(()) } fn springy_ship( @@ -81,7 +86,7 @@ fn springy_ship( mut ship: Query<&mut Transform, With>, mut desired_dir: Local<(Vec3, Quat)>, mut smoothed_rot: Local>, -) { +) -> Result { desired_dir.0 = DVec3::new(cam_input.right, cam_input.up, -cam_input.forward).as_vec3() * (1.0 + cam_input.boost as u8 as f32); @@ -89,7 +94,7 @@ fn springy_ship( smoothed_rot.push_front(DVec3::new(cam_input.pitch, cam_input.yaw, cam_input.roll).as_vec3()); let avg_rot = smoothed_rot.iter().sum::() / smoothed_rot.len() as f32; - use std::f32::consts::*; + use core::f32::consts::*; desired_dir.1 = Quat::IDENTITY.slerp( Quat::from_euler( EulerRot::XYZ, @@ -100,12 +105,14 @@ fn springy_ship( 0.2, ) * Quat::from_rotation_y(PI); - ship.single_mut().translation = ship - .single_mut() + ship.single_mut()?.translation = ship + .single_mut()? .translation .lerp(desired_dir.0 * Vec3::new(0.5, 0.5, -2.0), 0.02); - ship.single_mut().rotation = ship.single_mut().rotation.slerp(desired_dir.1, 0.02); + ship.single_mut()?.rotation = ship.single_mut()?.rotation.slerp(desired_dir.1, 0.02); + + Ok(()) } fn spawn_solar_system( @@ -218,7 +225,7 @@ fn spawn_solar_system( camera.insert(( FloatingOrigin, Transform::from_translation(cam_pos).looking_to(Vec3::NEG_Z, Vec3::X), - big_space::camera::CameraController::default() // Built-in camera controller + CameraController::default() // Built-in camera controller .with_speed_bounds([0.1, 10e35]) .with_smoothness(0.98, 0.98) .with_speed(1.0), @@ -244,7 +251,7 @@ fn spawn_solar_system( camera.with_child(( Spaceship, SceneRoot(asset_server.load("models/low_poly_spaceship/scene.gltf#Scene0")), - Transform::from_rotation(Quat::from_rotation_y(std::f32::consts::PI)), + Transform::from_rotation(Quat::from_rotation_y(core::f32::consts::PI)), )); }); }); @@ -276,10 +283,8 @@ fn cursor_grab_system( mut cam: ResMut, btn: Res>, key: Res>, -) { - let Some(mut window) = windows.get_single_mut().ok() else { - return; - }; +) -> Result<()> { + let mut window = windows.single_mut()?; if btn.just_pressed(MouseButton::Right) { window.cursor_options.grab_mode = bevy::window::CursorGrabMode::Locked; @@ -294,4 +299,6 @@ fn cursor_grab_system( // window.mode = WindowMode::Windowed; cam.defaults_disabled = true; } + + Ok(()) } diff --git a/examples/small_scale.rs b/examples/small_scale.rs index d7d91ed..2b296df 100644 --- a/examples/small_scale.rs +++ b/examples/small_scale.rs @@ -9,6 +9,7 @@ use bevy::prelude::*; use bevy_math::DVec3; use big_space::prelude::*; +use tracing::info; const UNIVERSE_DIA: f64 = 8.8e26; // Diameter of the observable universe const PROTON_DIA: f32 = 1.68e-15; // Diameter of a proton @@ -16,10 +17,10 @@ const PROTON_DIA: f32 = 1.68e-15; // Diameter of a proton fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), FloatingOriginDebugPlugin::default(), // Draws cell AABBs and grids - big_space::camera::CameraControllerPlugin::default(), // Compatible controller + CameraControllerPlugin::default(), // Compatible controller )) .add_systems(Startup, setup_scene) .add_systems(Update, (bounce_atoms, toggle_cam_pos)) @@ -75,14 +76,14 @@ fn setup_scene( Transform::from_xyz(0.0, 0.0, PROTON_DIA * 2.0), grid_cell, FloatingOrigin, - big_space::camera::CameraController::default(), + CameraController::default(), )); // A space ship root_grid.spawn_spatial(( SceneRoot(asset_server.load("models/low_poly_spaceship/scene.gltf#Scene0")), Transform::from_xyz(0.0, 0.0, 2.5) - .with_rotation(Quat::from_rotation_y(std::f32::consts::PI)), + .with_rotation(Quat::from_rotation_y(core::f32::consts::PI)), grid_cell, )); }); @@ -104,12 +105,15 @@ fn toggle_cam_pos( grid: Query<&Grid>, keyboard: Res>, protons: Query<&GlobalTransform, With>, -) { +) -> Result { if !keyboard.just_pressed(KeyCode::KeyT) { - return; + return Ok(()); } - *cam.single_mut() = if *toggle { - grid.single().translation_to_grid(DVec3::X * UNIVERSE_DIA).0 + *cam.single_mut()? = if *toggle { + grid.single() + .unwrap() + .translation_to_grid(DVec3::X * UNIVERSE_DIA) + .0 } else { GridCell::ZERO }; @@ -120,4 +124,5 @@ fn toggle_cam_pos( for proton in &protons { info!("Proton x coord: {}", proton.translation().x); } + Ok(()) } diff --git a/examples/spatial_hash.rs b/examples/spatial_hash.rs index 4502fc3..9792de9 100644 --- a/examples/spatial_hash.rs +++ b/examples/spatial_hash.rs @@ -1,14 +1,14 @@ -use std::hash::Hasher; +//! Demonstrates the included optional spatial hashing and partitioning of grid cells. use bevy::{ - core_pipeline::{bloom::Bloom, fxaa::Fxaa, tonemapping::Tonemapping}, + core_pipeline::{bloom::Bloom, tonemapping::Tonemapping}, prelude::*, }; -use bevy_ecs::entity::EntityHasher; +use bevy_ecs::{entity::EntityHasher, relationship::Relationship}; use bevy_math::DVec3; use big_space::prelude::*; +use core::hash::Hasher; use noise::{NoiseFn, Simplex}; -use smallvec::SmallVec; use turborand::prelude::*; // Try bumping this up to really stress test. I'm able to push a million entities with an M3 Max. @@ -21,11 +21,11 @@ const PERCENT_STATIC: f32 = 0.99; fn main() { App::new() .add_plugins(( - DefaultPlugins, + DefaultPlugins.build().disable::(), BigSpacePlugin::default(), GridHashPlugin::<()>::default(), GridPartitionPlugin::<()>::default(), - big_space::camera::CameraControllerPlugin::default(), + CameraControllerPlugin::default(), )) .add_systems(Startup, (spawn, setup_ui)) .add_systems( @@ -69,7 +69,7 @@ impl FromWorld for MaterialPresets { let mut meshes = world.resource_mut::>(); let sphere = meshes.add( - Sphere::new(HALF_WIDTH / (1_000_000_f32).powf(0.33) * 0.5) + Sphere::new(HALF_WIDTH / 1_000_000_f32.powf(0.33) * 0.5) .mesh() .ico(0) .unwrap(), @@ -89,10 +89,12 @@ fn draw_partitions( partitions: Res, grids: Query<(&GlobalTransform, &Grid)>, camera: Query<&GridHash, With>, -) { +) -> Result { + let camera = camera.single()?; + for (id, p) in partitions.iter().take(10_000) { let Ok((transform, grid)) = grids.get(p.grid()) else { - return; + return Ok(()); }; let l = grid.cell_edge_length(); @@ -102,7 +104,7 @@ fn draw_partitions( let hue = (f % 360) as f32; p.iter() - .filter(|hash| *hash != camera.single()) + .filter(|hash| *hash != camera) .take(1_000) .for_each(|h| { let center = [h.cell().x as i32, h.cell().y as i32, h.cell().z as i32]; @@ -110,7 +112,7 @@ fn draw_partitions( .with_scale(Vec3::splat(l)); gizmos.cuboid( transform.mul_transform(local_trans), - Hsla::new(hue, 1.0, 0.5, 0.05), + Hsla::new(hue, 1.0, 0.5, 0.2), ); }); @@ -123,19 +125,20 @@ fn draw_partitions( gizmos.cuboid( transform.mul_transform(local_trans), - Hsla::new(hue, 1.0, 0.5, 0.2), + Hsla::new(hue, 1.0, 0.5, 0.9), ); } + + Ok(()) } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn move_player( time: Res