diff --git a/.github/bors.toml b/.github/bors.toml index 0380d3003e1a92..7c237230f15cae 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -14,6 +14,9 @@ status = [ "check-compiles", "build-and-install-on-iOS", "run-examples-on-windows-dx12", + "build-without-default-features (bevy)", + "build-without-default-features (bevy_ecs)", + "build-without-default-features (bevy_reflect)", ] use_squash_merge = true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1994a255c88bf1..41184438f9616d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: env: CARGO_TERM_COLOR: always - NIGHTLY_TOOLCHAIN: nightly-2022-07-13 + NIGHTLY_TOOLCHAIN: nightly jobs: build: @@ -28,6 +28,10 @@ jobs: ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-build-stable-${{ hashFiles('**/Cargo.toml') }} + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true - name: Install alsa and udev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev if: runner.os == 'linux' @@ -93,9 +97,8 @@ jobs: # https://github.com/rust-lang/miri#miri--z-flags-and-environment-variables # -Zmiri-disable-isolation is needed because our executor uses `fastrand` which accesses system time. # -Zmiri-permissive-provenance disables warnings against int2ptr casts (since those are used by once_cell) - # -Zmiri-disable-weak-memory-emulation works around https://github.com/bevyengine/bevy/issues/5164. # -Zmiri-ignore-leaks is necessary because a bunch of tests don't join all threads before finishing. - MIRIFLAGS: -Zmiri-ignore-leaks -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-disable-weak-memory-emulation + MIRIFLAGS: -Zmiri-ignore-leaks -Zmiri-disable-isolation -Zmiri-permissive-provenance check-compiles: runs-on: ubuntu-latest @@ -195,8 +198,9 @@ jobs: with: toolchain: stable - name: Build bevy + # this uses the same command as when running the example to ensure build is reused run: | - cargo build --features "bevy_ci_testing,trace,trace_chrome" + TRACE_CHROME=trace-alien_cake_addict.json CI_TESTING_CONFIG=.github/example-run/alien_cake_addict.ron cargo build --example alien_cake_addict --features "bevy_ci_testing,trace,trace_chrome" - name: Run examples run: | for example in .github/example-run/*.ron; do diff --git a/.github/workflows/validation-jobs.yml b/.github/workflows/validation-jobs.yml index e64445fb7ec34a..f280a70a5c121f 100644 --- a/.github/workflows/validation-jobs.yml +++ b/.github/workflows/validation-jobs.yml @@ -41,7 +41,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: toolchain: stable - + - uses: actions/cache@v3 with: path: | @@ -51,15 +51,15 @@ jobs: ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-build-android-${{ hashFiles('**/Cargo.toml') }} - + - name: Install Android targets run: rustup target add aarch64-linux-android armv7-linux-androideabi - + - name: Install Cargo APK run: cargo install --force cargo-apk - + - name: Build APK - run: cargo apk build --example android_example + run: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME cargo apk build --example android_example run-examples-on-windows-dx12: runs-on: windows-latest @@ -82,8 +82,10 @@ jobs: key: ${{ runner.os }}-windows-run-examples-${{ hashFiles('**/Cargo.toml') }} - name: Build bevy + shell: bash + # this uses the same command as when running the example to ensure build is reused run: | - cargo build --features "bevy_ci_testing" + WGPU_BACKEND=dx12 CI_TESTING_CONFIG=.github/example-run/alien_cake_addict.ron cargo build --example alien_cake_addict --features "bevy_ci_testing" - name: Run examples shell: bash @@ -145,10 +147,29 @@ jobs: # start a webserver python3 -m http.server --directory examples/wasm & - xvfb-run cargo run -p build-wasm-example -- --browsers chromium --browsers firefox --frames 25 --test shapes lighting text_debug breakout + xvfb-run cargo run -p build-wasm-example -- --browsers chromium --browsers firefox --frames 25 --test 2d_shapes lighting text_debug breakout - name: Save screenshots uses: actions/upload-artifact@v3 with: name: screenshots path: .github/start-wasm-example/screenshot-*.png + + build-without-default-features: + strategy: + matrix: + crate: [bevy_ecs, bevy_reflect, bevy] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - name: Install alsa and udev + run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev + - name: Build + run: cargo build -p ${{ matrix.crate }} --no-default-features + env: + CARGO_INCREMENTAL: 0 + RUSTFLAGS: "-C debuginfo=0 -D warnings" diff --git a/.gitignore b/.gitignore index 48bbc7e0e1c915..d1e9822c5bb7f4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ Cargo.lock /.idea /.vscode /benches/target + +# Generated by "examples/scene/scene.rs" +assets/scenes/load_scene_example-new.scn.ron diff --git a/CHANGELOG.md b/CHANGELOG.md index a70b76da9460dd..efeaf2945eda80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,518 @@ current changes on git with [previous release tags][git_tag_comparison]. [git_tag_comparison]: https://github.com/bevyengine/bevy/compare/v0.6.0...main +## Version 0.8.0 (2022-07-30) + +### Added + +- [Callable PBR functions][4939] +- [Spotlights][4715] +- [Camera Driven Rendering][4745] +- [Camera Driven Viewports][4898] +- [Visibilty Inheritance, universal `ComputedVisibility`, and `RenderLayers` support][5310] +- [Better Materials: `AsBindGroup` trait and derive, simpler `Material` trait][5053] +- [Derive `AsBindGroup` Improvements: Better errors, more options, update examples][5364] +- [Support `AsBindGroup` for 2d materials as well][5312] +- [Parallel Frustum Culling][4489] +- [Hierarchy commandization][4197] +- [Generate vertex tangents using mikktspace][3872] +- [Add a `SpatialBundle` with `Visibility` and `Transform` components][5344] +- [Add `RegularPolygon` and `Circle` meshes][3730] +- [Add a `SceneBundle` to spawn a scene][2424] +- [Allow higher order systems][4833] +- [Add global `init()` and `get()` accessors for all newtyped `TaskPools`][2250] +- [Add reusable shader functions for transforming position/normal/tangent][4901] +- [Add support for vertex colors][4528] +- [Add support for removing attributes from meshes][5254] +- [Add option to center a window][4999] +- [Add `depth_load_op` configuration field to `Camera3d`][4904] +- [Refactor `Camera` methods and add viewport rect][4948] +- [Add `TextureFormat::R16Unorm` support for `Image`][5249] +- [Add a `VisibilityBundle` with `Visibility` and `ComputedVisibility` components][5335] +- [Add ExtractResourcePlugin][3745] +- [Add depth_bias to SpecializedMaterial][4101] +- [Added `offset` parameter to `TextureAtlas::from_grid_with_padding`][4836] +- [Add the possibility to create custom 2d orthographic cameras][4048] +- [bevy_render: Add `attributes` and `attributes_mut` methods to `Mesh`][3927] +- [Add helper methods for rotating `Transform`s][5151] +- [Enable wgpu profiling spans when using bevy's trace feature][5182] +- [bevy_pbr: rework `extract_meshes`][4240] +- [Add `inverse_projection` and `inverse_view_proj` fields to shader view uniform][5119] +- [Add `ViewRangefinder3d` to reduce boilerplate when enqueuing standard 3D `PhaseItems`][5014] +- [Create `bevy_ptr` standalone crate][4653] +- [Add `IntoIterator` impls for `&Query` and `&mut Query`][4692] +- [Add untyped APIs for `Components` and `Resources`][4447] +- [Add infallible resource getters for `WorldCell`][4104] +- [Add `get_change_ticks` method to `EntityRef` and `EntityMut`][2539] +- [Add comparison methods to `FilteredAccessSet`][4211] +- [Add `Commands::new_from_entities`][4423] +- [Add `QueryState::get_single_unchecked_manual` and its family members][4841] +- [Add `ParallelCommands` system parameter][4749] +- [Add methods for querying lists of entities][4879] +- [Implement `FusedIterator` for eligible `Iterator` types][4942] +- [Add `component_id()` function to `World` and `Components`][5066] +- [Add ability to inspect entity's components][5136] +- [Add a more helpful error to help debug panicking command on despawned entity][5198] +- [Add `ExactSizeIterator` implementation for `QueryCombinatonIter`][5148] +- [Added the `ignore_fields` attribute to the derive macros for `*Label` types][5366] +- [Exact sized event iterators][3863] +- [Add a `clear()` method to the `EventReader` that consumes the iterator][4693] +- [Add helpers to send `Events` from `World`][5355] +- [Add file metadata to `AssetIo`][2123] +- [Add missing audio/ogg file extensions: .oga, .spx][4703] +- [Add `reload_asset` method to `AssetServer`][5106] +- [Allow specifying chrome tracing file path using an environment variable][4618] +- [Create a simple tool to compare traces between executions][4628] +- [Add a tracing span for run criteria][4709] +- [Add tracing spans for `Query::par_for_each` and its variants.][4711] +- [Add a `release_all` method on `Input`][5011] +- [Add a `reset_all` method on `Input`][5015] +- [Add a helper tool to build examples for wasm][4776] +- [bevy_reflect: add a `ReflectFromPtr` type to create `&dyn Reflect` from a `*const ()`][4475] +- [Add a `ReflectDefault` type and add `#[reflect(Default)]` to all component types that implement Default and are user facing][3733] +- [Add a macro to implement `Reflect` for struct types and migrate glam types to use this for reflection][4540] +- [bevy_reflect: reflect arrays][4701] +- [bevy_reflect: reflect char][4790] +- [bevy_reflect: add `GetTypeRegistration` impl for reflected tuples][4226] +- [Add reflection for `Resources`][5175] +- [bevy_reflect: add `as_reflect` and `as_reflect_mut` methods on `Reflect`][4350] +- [Add an `apply_or_insert` method to `ReflectResource` and `ReflectComponent`][5201] +- [bevy_reflect: `IntoIter` for `DynamicList` and `DynamicMap`][4108] +- [bevy_reflect: Add `PartialEq` to reflected `f32`s and `f64`s][4217] +- [Create mutable versions of `TypeRegistry` methods][4484] +- [bevy_reflect: add a `get_boxed` method to `reflect_trait`][4120] +- [bevy_reflect: add `#[reflect(default)]` attribute for `FromReflect`][4140] +- [bevy_reflect: add statically available type info for reflected types][4042] +- [Add an `assert_is_exclusive_system` function][5275] +- [bevy_ui: add a multi-windows check for `Interaction` (we dont yet support multiple windows)][5225] + +### Changed + +- [Depend on Taffy (a Dioxus and Bevy-maintained fork of Stretch)][4716] +- [Use lifetimed, type erased pointers in bevy_ecs][3001] +- [Migrate to `encase` from `crevice`][4339] +- [Update `wgpu` to 0.13][5168] +- [Pointerfication followup: Type safety and cleanup][4621] +- [bevy_ptr works in no_std environments][4760] +- [Fail to compile on 16-bit platforms][4736] +- [Improve ergonomics and reduce boilerplate around creating text elements][5343] +- [Don't cull `Ui` nodes that have a rotation][5389] +- [Rename `ElementState` to `ButtonState`][4314] +- [Move `Size` to `bevy_ui`][4285] +- [Move `Rect` to `bevy_ui` and rename it to `UiRect`][4276] +- [Modify `FontAtlas` so that it can handle fonts of any size][3592] +- [Rename `CameraUi`][5234] +- [Remove `task_pool` parameter from `par_for_each(_mut)`][4705] +- [Copy `TaskPool` resoures to sub-Apps][4792] +- [Allow closing windows at runtime][3575] +- [Move the configuration of the `WindowPlugin` to a `Resource`][5227] +- [Optionally resize `Window` canvas element to fit parent element][4726] +- [Change window resolution types from tuple to `Vec2`][5276] +- [Update time by sending frame `Instant` through a channel][4744] +- [Split time functionality into `bevy_time`][4187] +- [Split mesh shader files to make the shaders more reusable][4867] +- [Set `naga` capabilities corresponding to `wgpu` features][4824] +- [Separate out PBR lighting, shadows, clustered forward, and utils from pbr.wgsl][4938] +- [Separate PBR and tonemapping into 2 functions][5078] +- [Make `RenderStage::Extract` run on the render world][4402] +- [Change default `FilterMode` of `Image` to `Linear`][4465] +- [bevy_render: Fix KTX2 UASTC format mapping][4569] +- [Allow rendering meshes without UV coordinate data][5222] +- [Validate vertex attribute format on insertion][5259] +- [Use `Affine3A` for `GlobalTransform`to allow any affine transformation][4379] +- [Recalculate entity `AABB`s when meshes change][4944] +- [Change `check_visibility` to use thread-local queues instead of a channel][4663] +- [Allow unbatched render phases to use unstable sorts][5049] +- [Extract resources into their target location][5271] +- [Enable loading textures of unlimited size][5305] +- [Do not create nor execute render passes which have no `PhaseItems` to draw][4643] +- [Filter material handles on extraction][4178] +- [Apply vertex colors to `ColorMaterial` and `Mesh2D`][4812] +- [Make `MaterialPipelineKey` fields public][4508] +- [Simplified API to get NDC from camera and world position][4041] +- [Set `alpha_mode` based on alpha value][4658] +- [Make `Wireframe` respect `VisibleEntities`][4660] +- [Use const `Vec2` in lights cluster and bounding box when possible][4602] +- [Make accessors for mesh vertices and indices public][3906] +- [Use `BufferUsages::UNIFORM` for `SkinnedMeshUniform`][4816] +- [Place origin of `OrthographicProjection` at integer pixel when using `ScalingMode::WindowSize`][4085] +- [Make `ScalingMode` more flexible][3253] +- [Move texture sample out of branch in `prepare_normal`][5129] +- [Make the fields of the `Material2dKey` public][5212] +- [Use collect to build mesh attributes][5255] +- [Replace `ReadOnlyFetch` with `ReadOnlyWorldQuery`][4626] +- [Replace `ComponentSparseSet`'s internals with a `Column`][4909] +- [Remove QF generics from all `Query/State` methods and types][5170] +- [Remove `.system()`][4499] +- [Make change lifespan deterministic and update docs][3956] +- [Make derived `SystemParam` readonly if possible][4650] +- [Merge `matches_archetype` and `matches_table`][4807] +- [Allows conversion of mutable queries to immutable queries][5376] +- [Skip `drop` when `needs_drop` is `false`][4773] +- [Use u32 over usize for `ComponentSparseSet` indicies][4723] +- [Remove redundant `ComponentId` in `Column`][4855] +- [Directly copy moved `Table` components to the target location][5056] +- [`SystemSet::before` and `SystemSet::after` now take `AsSystemLabel`][4503] +- [Converted exclusive systems to parallel systems wherever possible][2774] +- [Improve `size_hint` on `QueryIter`][4244] +- [Improve debugging tools for change detection][4160] +- [Make `RunOnce` a non-manual `System` impl][3922] +- [Apply buffers in `ParamSet`][4677] +- [Don't allocate for `ComponentDescriptors` of non-dynamic component types][4725] +- [Mark mutable APIs under ECS storage as `pub(crate)`][5065] +- [Update `ExactSizeIterator` impl to support archetypal filters (`With`, `Without`)][5124] +- [Removed world cell from places where split multable access is not needed][5167] +- [Add Events to `bevy_ecs` prelude][5159] +- [Improve `EntityMap` API][5231] +- [Implement `From` for `ShouldRun`.][5306] +- [Allow iter combinations on custom world queries][5286] +- [Simplify design for `*Label`s][4957] +- [Tidy up the code of events][4713] +- [Rename `send_default_event` to `send_event_default` on world][5383] +- [enable optional dependencies to stay optional][5023] +- [Remove the dependency cycles][5171] +- [Enforce type safe usage of Handle::get][4794] +- [Export anyhow::error for custom asset loaders][5359] +- [Update `shader_material_glsl` example to include texture sampling][5215] +- [Remove unused code in game of life shader][5349] +- [Make the contributor birbs bounce to the window height][5274] +- [Improve Gamepad D-Pad Button Detection][5220] +- [bevy_reflect: support map insertio][5173] +- [bevy_reflect: improve debug formatting for reflected types][4218] +- [bevy_reflect_derive: big refactor tidying up the code][4712] +- [bevy_reflect: small refactor and default `Reflect` methods][4739] +- [Make `Reflect` safe to implement][5010] +- [`bevy_reflect`: put `serialize` into external `ReflectSerialize` type][4782] +- [Remove `Serialize` impl for `dyn Array` and friends][4780] +- [Re-enable `#[derive(TypeUuid)]` for generics][4118] +- [Move primitive type registration into `bevy_reflect`][4844] +- [Implement reflection for more `glam` types][5194] +- [Make `reflect_partial_eq` return more accurate results][5210] +- [Make public macros more robust with `$crate`][4655] +- [Ensure that the parent is always the expected entity][4717] +- [Support returning data out of `with_children`][4708] +- [Remove `EntityMut::get_unchecked`][4547] +- [Diagnostics: meaningful error when graph node has wrong number of inputs][4924] +- [Remove redundant `Size` import][5339] +- [Export and register `Mat2`.][5324] +- [Implement `Debug` for `Gamepads`][5291] +- [Update codebase to use `IntoIterator` where possible.][5269] +- [Rename `headless_defaults` example to `no_renderer` for clarity][5263] +- [Remove dead `SystemLabelMarker` struct][5190] +- [bevy_reflect: remove `glam` from a test which is active without the glam feature][5195] +- [Disable vsync for stress tests][5187] +- [Move `get_short_name` utility method from `bevy_reflect` into `bevy_utils`][5174] +- [Derive `Default` for enums where possible][5158] +- [Implement `Eq` and `PartialEq` for `MouseScrollUnit`][5048] +- [Some cleanup for `bevy_ptr`][4668] +- [Move float_ord from `bevy_core` to `bevy_utils`][4189] +- [Remove unused `CountdownEvent`][4290] +- [Some minor cleanups of asset_server][4604] +- [Use `elapsed()` on `Instant`][4599] +- [Make paused `Timers` update `just_finished` on tick][4445] +- [bevy_utils: remove hardcoded log level limit][4580] +- [Make `Time::update_with_instant` public for use in tests][4469] +- [Do not impl Component for Task][4113] +- [Remove nonexistent `WgpuResourceDiagnosticsPlugin`][4541] +- [Update ndk-glue requirement from 0.5 to 0.6][3624] +- [Update tracing-tracy requirement from 0.8.0 to 0.9.0][4786] +- [update image to 0.24][4121] +- [update xshell to 0.2][4789] +- [Update gilrs to v0.9][4848] +- [bevy_log: upgrade to tracing-tracy 0.10.0][4991] +- [update hashbrown to 0.12][5035] +- [Update `clap` to 3.2 in tools using `value_parser`][5031] +- [Updated `glam` to `0.21`.][5142] +- [Update Notify Dependency][5396] + +### Fixed + +- [bevy_ui: keep `Color` as 4 `f32`s][4494] +- [Fix issues with bevy on android other than the rendering][5130] +- [Update layout/style when scale factor changes too][4689] +- [Fix `Overflow::Hidden` so it works correctly with `scale_factor_override`][3854] +- [Fix `bevy_ui` touch input][4099] +- [Fix physical viewport calculation][5055] +- [Minimally fix the known unsoundness in `bevy_mikktspace`][5299] +- [Make `Transform` propagation correct in the presence of updated children][4608] +- [`StorageBuffer` uses wrong type to calculate the buffer size.][4557] +- [Fix confusing near and far fields in Camera][4457] +- [Allow minimising window if using a 2d camera][4527] +- [WGSL: use correct syntax for matrix access][5039] +- [Gltf: do not import `IoTaskPool` in wasm][5038] +- [Fix skinned mesh normal handling in mesh shader][5095] +- [Don't panic when `StandardMaterial` `normal_map` hasn't loaded yet][5307] +- [Fix incorrect rotation in `Transform::rotate_around`][5300] +- [Fix `extract_wireframes`][5301] +- [Fix type parameter name conflicts of `#[derive(Bundle)]`][4636] +- [Remove unnecessary `unsafe impl` of `Send+Sync` for `ParallelSystemContainer`][5137] +- [Fix line material shader][5348] +- [Fix `mouse_clicked` check for touch][2029] +- [Fix unsoundness with `Or`/`AnyOf`/`Option` component access][4659] +- [Improve soundness of `CommandQueue`][4863] +- [Fix some memory leaks detected by miri][4959] +- [Fix Android example icon][4076] +- [Fix broken `WorldCell` test][5009] +- [Bugfix `State::set` transition condition infinite loop][4890] +- [Fix crash when using `Duration::MAX`][4900] +- [Fix release builds: Move asserts under `#[cfg(debug_assertions)]`][4871] +- [Fix frame count being a float][4493] +- [Fix "unused" warnings when compiling with `render` feature but without `animation`][4714] +- [Fix re-adding a plugin to a `PluginGroup`][2039] +- [Fix torus normals][4520] +- [Add `NO_STORAGE_BUFFERS_SUPPORT` shaderdef when needed][4949] + +[2029]: https://github.com/bevyengine/bevy/pull/2029 +[2039]: https://github.com/bevyengine/bevy/pull/2039 +[2123]: https://github.com/bevyengine/bevy/pull/2123 +[2250]: https://github.com/bevyengine/bevy/pull/2250 +[2424]: https://github.com/bevyengine/bevy/pull/2424 +[2539]: https://github.com/bevyengine/bevy/pull/2539 +[2774]: https://github.com/bevyengine/bevy/pull/2774 +[3001]: https://github.com/bevyengine/bevy/pull/3001 +[3253]: https://github.com/bevyengine/bevy/pull/3253 +[3575]: https://github.com/bevyengine/bevy/pull/3575 +[3592]: https://github.com/bevyengine/bevy/pull/3592 +[3624]: https://github.com/bevyengine/bevy/pull/3624 +[3730]: https://github.com/bevyengine/bevy/pull/3730 +[3733]: https://github.com/bevyengine/bevy/pull/3733 +[3745]: https://github.com/bevyengine/bevy/pull/3745 +[3854]: https://github.com/bevyengine/bevy/pull/3854 +[3863]: https://github.com/bevyengine/bevy/pull/3863 +[3872]: https://github.com/bevyengine/bevy/pull/3872 +[3906]: https://github.com/bevyengine/bevy/pull/3906 +[3922]: https://github.com/bevyengine/bevy/pull/3922 +[3927]: https://github.com/bevyengine/bevy/pull/3927 +[3956]: https://github.com/bevyengine/bevy/pull/3956 +[4041]: https://github.com/bevyengine/bevy/pull/4041 +[4042]: https://github.com/bevyengine/bevy/pull/4042 +[4048]: https://github.com/bevyengine/bevy/pull/4048 +[4076]: https://github.com/bevyengine/bevy/pull/4076 +[4085]: https://github.com/bevyengine/bevy/pull/4085 +[4099]: https://github.com/bevyengine/bevy/pull/4099 +[4101]: https://github.com/bevyengine/bevy/pull/4101 +[4104]: https://github.com/bevyengine/bevy/pull/4104 +[4108]: https://github.com/bevyengine/bevy/pull/4108 +[4113]: https://github.com/bevyengine/bevy/pull/4113 +[4118]: https://github.com/bevyengine/bevy/pull/4118 +[4120]: https://github.com/bevyengine/bevy/pull/4120 +[4121]: https://github.com/bevyengine/bevy/pull/4121 +[4140]: https://github.com/bevyengine/bevy/pull/4140 +[4160]: https://github.com/bevyengine/bevy/pull/4160 +[4178]: https://github.com/bevyengine/bevy/pull/4178 +[4187]: https://github.com/bevyengine/bevy/pull/4187 +[4189]: https://github.com/bevyengine/bevy/pull/4189 +[4197]: https://github.com/bevyengine/bevy/pull/4197 +[4211]: https://github.com/bevyengine/bevy/pull/4211 +[4217]: https://github.com/bevyengine/bevy/pull/4217 +[4218]: https://github.com/bevyengine/bevy/pull/4218 +[4226]: https://github.com/bevyengine/bevy/pull/4226 +[4240]: https://github.com/bevyengine/bevy/pull/4240 +[4244]: https://github.com/bevyengine/bevy/pull/4244 +[4276]: https://github.com/bevyengine/bevy/pull/4276 +[4285]: https://github.com/bevyengine/bevy/pull/4285 +[4290]: https://github.com/bevyengine/bevy/pull/4290 +[4314]: https://github.com/bevyengine/bevy/pull/4314 +[4339]: https://github.com/bevyengine/bevy/pull/4339 +[4350]: https://github.com/bevyengine/bevy/pull/4350 +[4379]: https://github.com/bevyengine/bevy/pull/4379 +[4402]: https://github.com/bevyengine/bevy/pull/4402 +[4423]: https://github.com/bevyengine/bevy/pull/4423 +[4445]: https://github.com/bevyengine/bevy/pull/4445 +[4447]: https://github.com/bevyengine/bevy/pull/4447 +[4457]: https://github.com/bevyengine/bevy/pull/4457 +[4465]: https://github.com/bevyengine/bevy/pull/4465 +[4469]: https://github.com/bevyengine/bevy/pull/4469 +[4475]: https://github.com/bevyengine/bevy/pull/4475 +[4484]: https://github.com/bevyengine/bevy/pull/4484 +[4489]: https://github.com/bevyengine/bevy/pull/4489 +[4493]: https://github.com/bevyengine/bevy/pull/4493 +[4494]: https://github.com/bevyengine/bevy/pull/4494 +[4499]: https://github.com/bevyengine/bevy/pull/4499 +[4503]: https://github.com/bevyengine/bevy/pull/4503 +[4508]: https://github.com/bevyengine/bevy/pull/4508 +[4520]: https://github.com/bevyengine/bevy/pull/4520 +[4527]: https://github.com/bevyengine/bevy/pull/4527 +[4528]: https://github.com/bevyengine/bevy/pull/4528 +[4540]: https://github.com/bevyengine/bevy/pull/4540 +[4541]: https://github.com/bevyengine/bevy/pull/4541 +[4547]: https://github.com/bevyengine/bevy/pull/4547 +[4557]: https://github.com/bevyengine/bevy/pull/4557 +[4569]: https://github.com/bevyengine/bevy/pull/4569 +[4580]: https://github.com/bevyengine/bevy/pull/4580 +[4599]: https://github.com/bevyengine/bevy/pull/4599 +[4602]: https://github.com/bevyengine/bevy/pull/4602 +[4604]: https://github.com/bevyengine/bevy/pull/4604 +[4608]: https://github.com/bevyengine/bevy/pull/4608 +[4618]: https://github.com/bevyengine/bevy/pull/4618 +[4621]: https://github.com/bevyengine/bevy/pull/4621 +[4626]: https://github.com/bevyengine/bevy/pull/4626 +[4628]: https://github.com/bevyengine/bevy/pull/4628 +[4636]: https://github.com/bevyengine/bevy/pull/4636 +[4643]: https://github.com/bevyengine/bevy/pull/4643 +[4650]: https://github.com/bevyengine/bevy/pull/4650 +[4653]: https://github.com/bevyengine/bevy/pull/4653 +[4655]: https://github.com/bevyengine/bevy/pull/4655 +[4658]: https://github.com/bevyengine/bevy/pull/4658 +[4659]: https://github.com/bevyengine/bevy/pull/4659 +[4660]: https://github.com/bevyengine/bevy/pull/4660 +[4663]: https://github.com/bevyengine/bevy/pull/4663 +[4668]: https://github.com/bevyengine/bevy/pull/4668 +[4677]: https://github.com/bevyengine/bevy/pull/4677 +[4689]: https://github.com/bevyengine/bevy/pull/4689 +[4692]: https://github.com/bevyengine/bevy/pull/4692 +[4693]: https://github.com/bevyengine/bevy/pull/4693 +[4701]: https://github.com/bevyengine/bevy/pull/4701 +[4703]: https://github.com/bevyengine/bevy/pull/4703 +[4705]: https://github.com/bevyengine/bevy/pull/4705 +[4708]: https://github.com/bevyengine/bevy/pull/4708 +[4709]: https://github.com/bevyengine/bevy/pull/4709 +[4711]: https://github.com/bevyengine/bevy/pull/4711 +[4712]: https://github.com/bevyengine/bevy/pull/4712 +[4713]: https://github.com/bevyengine/bevy/pull/4713 +[4714]: https://github.com/bevyengine/bevy/pull/4714 +[4715]: https://github.com/bevyengine/bevy/pull/4715 +[4716]: https://github.com/bevyengine/bevy/pull/4716 +[4717]: https://github.com/bevyengine/bevy/pull/4717 +[4723]: https://github.com/bevyengine/bevy/pull/4723 +[4725]: https://github.com/bevyengine/bevy/pull/4725 +[4726]: https://github.com/bevyengine/bevy/pull/4726 +[4736]: https://github.com/bevyengine/bevy/pull/4736 +[4739]: https://github.com/bevyengine/bevy/pull/4739 +[4744]: https://github.com/bevyengine/bevy/pull/4744 +[4745]: https://github.com/bevyengine/bevy/pull/4745 +[4749]: https://github.com/bevyengine/bevy/pull/4749 +[4760]: https://github.com/bevyengine/bevy/pull/4760 +[4773]: https://github.com/bevyengine/bevy/pull/4773 +[4776]: https://github.com/bevyengine/bevy/pull/4776 +[4780]: https://github.com/bevyengine/bevy/pull/4780 +[4782]: https://github.com/bevyengine/bevy/pull/4782 +[4786]: https://github.com/bevyengine/bevy/pull/4786 +[4789]: https://github.com/bevyengine/bevy/pull/4789 +[4790]: https://github.com/bevyengine/bevy/pull/4790 +[4792]: https://github.com/bevyengine/bevy/pull/4792 +[4794]: https://github.com/bevyengine/bevy/pull/4794 +[4807]: https://github.com/bevyengine/bevy/pull/4807 +[4812]: https://github.com/bevyengine/bevy/pull/4812 +[4816]: https://github.com/bevyengine/bevy/pull/4816 +[4824]: https://github.com/bevyengine/bevy/pull/4824 +[4833]: https://github.com/bevyengine/bevy/pull/4833 +[4836]: https://github.com/bevyengine/bevy/pull/4836 +[4841]: https://github.com/bevyengine/bevy/pull/4841 +[4844]: https://github.com/bevyengine/bevy/pull/4844 +[4848]: https://github.com/bevyengine/bevy/pull/4848 +[4855]: https://github.com/bevyengine/bevy/pull/4855 +[4863]: https://github.com/bevyengine/bevy/pull/4863 +[4867]: https://github.com/bevyengine/bevy/pull/4867 +[4871]: https://github.com/bevyengine/bevy/pull/4871 +[4879]: https://github.com/bevyengine/bevy/pull/4879 +[4890]: https://github.com/bevyengine/bevy/pull/4890 +[4898]: https://github.com/bevyengine/bevy/pull/4898 +[4900]: https://github.com/bevyengine/bevy/pull/4900 +[4901]: https://github.com/bevyengine/bevy/pull/4901 +[4904]: https://github.com/bevyengine/bevy/pull/4904 +[4909]: https://github.com/bevyengine/bevy/pull/4909 +[4924]: https://github.com/bevyengine/bevy/pull/4924 +[4938]: https://github.com/bevyengine/bevy/pull/4938 +[4939]: https://github.com/bevyengine/bevy/pull/4939 +[4942]: https://github.com/bevyengine/bevy/pull/4942 +[4944]: https://github.com/bevyengine/bevy/pull/4944 +[4948]: https://github.com/bevyengine/bevy/pull/4948 +[4949]: https://github.com/bevyengine/bevy/pull/4949 +[4957]: https://github.com/bevyengine/bevy/pull/4957 +[4959]: https://github.com/bevyengine/bevy/pull/4959 +[4991]: https://github.com/bevyengine/bevy/pull/4991 +[4999]: https://github.com/bevyengine/bevy/pull/4999 +[5009]: https://github.com/bevyengine/bevy/pull/5009 +[5010]: https://github.com/bevyengine/bevy/pull/5010 +[5011]: https://github.com/bevyengine/bevy/pull/5011 +[5014]: https://github.com/bevyengine/bevy/pull/5014 +[5015]: https://github.com/bevyengine/bevy/pull/5015 +[5023]: https://github.com/bevyengine/bevy/pull/5023 +[5031]: https://github.com/bevyengine/bevy/pull/5031 +[5035]: https://github.com/bevyengine/bevy/pull/5035 +[5038]: https://github.com/bevyengine/bevy/pull/5038 +[5039]: https://github.com/bevyengine/bevy/pull/5039 +[5048]: https://github.com/bevyengine/bevy/pull/5048 +[5049]: https://github.com/bevyengine/bevy/pull/5049 +[5053]: https://github.com/bevyengine/bevy/pull/5053 +[5055]: https://github.com/bevyengine/bevy/pull/5055 +[5056]: https://github.com/bevyengine/bevy/pull/5056 +[5065]: https://github.com/bevyengine/bevy/pull/5065 +[5066]: https://github.com/bevyengine/bevy/pull/5066 +[5078]: https://github.com/bevyengine/bevy/pull/5078 +[5095]: https://github.com/bevyengine/bevy/pull/5095 +[5106]: https://github.com/bevyengine/bevy/pull/5106 +[5119]: https://github.com/bevyengine/bevy/pull/5119 +[5124]: https://github.com/bevyengine/bevy/pull/5124 +[5129]: https://github.com/bevyengine/bevy/pull/5129 +[5130]: https://github.com/bevyengine/bevy/pull/5130 +[5136]: https://github.com/bevyengine/bevy/pull/5136 +[5137]: https://github.com/bevyengine/bevy/pull/5137 +[5142]: https://github.com/bevyengine/bevy/pull/5142 +[5148]: https://github.com/bevyengine/bevy/pull/5148 +[5151]: https://github.com/bevyengine/bevy/pull/5151 +[5158]: https://github.com/bevyengine/bevy/pull/5158 +[5159]: https://github.com/bevyengine/bevy/pull/5159 +[5167]: https://github.com/bevyengine/bevy/pull/5167 +[5168]: https://github.com/bevyengine/bevy/pull/5168 +[5170]: https://github.com/bevyengine/bevy/pull/5170 +[5171]: https://github.com/bevyengine/bevy/pull/5171 +[5173]: https://github.com/bevyengine/bevy/pull/5173 +[5174]: https://github.com/bevyengine/bevy/pull/5174 +[5175]: https://github.com/bevyengine/bevy/pull/5175 +[5182]: https://github.com/bevyengine/bevy/pull/5182 +[5187]: https://github.com/bevyengine/bevy/pull/5187 +[5190]: https://github.com/bevyengine/bevy/pull/5190 +[5194]: https://github.com/bevyengine/bevy/pull/5194 +[5195]: https://github.com/bevyengine/bevy/pull/5195 +[5198]: https://github.com/bevyengine/bevy/pull/5198 +[5201]: https://github.com/bevyengine/bevy/pull/5201 +[5210]: https://github.com/bevyengine/bevy/pull/5210 +[5212]: https://github.com/bevyengine/bevy/pull/5212 +[5215]: https://github.com/bevyengine/bevy/pull/5215 +[5220]: https://github.com/bevyengine/bevy/pull/5220 +[5222]: https://github.com/bevyengine/bevy/pull/5222 +[5225]: https://github.com/bevyengine/bevy/pull/5225 +[5227]: https://github.com/bevyengine/bevy/pull/5227 +[5231]: https://github.com/bevyengine/bevy/pull/5231 +[5234]: https://github.com/bevyengine/bevy/pull/5234 +[5249]: https://github.com/bevyengine/bevy/pull/5249 +[5254]: https://github.com/bevyengine/bevy/pull/5254 +[5255]: https://github.com/bevyengine/bevy/pull/5255 +[5259]: https://github.com/bevyengine/bevy/pull/5259 +[5263]: https://github.com/bevyengine/bevy/pull/5263 +[5269]: https://github.com/bevyengine/bevy/pull/5269 +[5271]: https://github.com/bevyengine/bevy/pull/5271 +[5274]: https://github.com/bevyengine/bevy/pull/5274 +[5275]: https://github.com/bevyengine/bevy/pull/5275 +[5276]: https://github.com/bevyengine/bevy/pull/5276 +[5286]: https://github.com/bevyengine/bevy/pull/5286 +[5291]: https://github.com/bevyengine/bevy/pull/5291 +[5299]: https://github.com/bevyengine/bevy/pull/5299 +[5300]: https://github.com/bevyengine/bevy/pull/5300 +[5301]: https://github.com/bevyengine/bevy/pull/5301 +[5305]: https://github.com/bevyengine/bevy/pull/5305 +[5306]: https://github.com/bevyengine/bevy/pull/5306 +[5307]: https://github.com/bevyengine/bevy/pull/5307 +[5310]: https://github.com/bevyengine/bevy/pull/5310 +[5312]: https://github.com/bevyengine/bevy/pull/5312 +[5324]: https://github.com/bevyengine/bevy/pull/5324 +[5335]: https://github.com/bevyengine/bevy/pull/5335 +[5339]: https://github.com/bevyengine/bevy/pull/5339 +[5343]: https://github.com/bevyengine/bevy/pull/5343 +[5344]: https://github.com/bevyengine/bevy/pull/5344 +[5348]: https://github.com/bevyengine/bevy/pull/5348 +[5349]: https://github.com/bevyengine/bevy/pull/5349 +[5355]: https://github.com/bevyengine/bevy/pull/5355 +[5359]: https://github.com/bevyengine/bevy/pull/5359 +[5364]: https://github.com/bevyengine/bevy/pull/5364 +[5366]: https://github.com/bevyengine/bevy/pull/5366 +[5376]: https://github.com/bevyengine/bevy/pull/5376 +[5383]: https://github.com/bevyengine/bevy/pull/5383 +[5389]: https://github.com/bevyengine/bevy/pull/5389 +[5396]: https://github.com/bevyengine/bevy/pull/5396 + ## Version 0.7.0 (2022-04-15) ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ea8b75864c0e0..586513eb99b899 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,6 +119,8 @@ PRs are controversial if there is serious design discussion required, or a large 7. Large-scale code reorganization. 8. High levels of technical complexity. 9. Adding a dependency. +10. Touching licensing information (due to the level of precision required). +11. Adding root-level files (due to the high level of visibility). Finally, changes are "relatively uncontroversial" if they are neither trivial or controversial. Most PRs should fall into this category. @@ -222,7 +224,8 @@ This is incredibly valuable, easily distributed work, but requires a bit of guid * Accepted RFCs are not documentation: they serve only as a record of accepted decisions. [docs.rs](https://docs.rs/bevy) is built from out of the last release's documentation, which is written right in-line directly above the code it documents. -To view the current docs on `main` before you contribute, clone the `bevy` repo, and run `cargo doc --open`. +To view the current docs on `main` before you contribute, clone the `bevy` repo, and run `cargo doc --open` or go to [dev-docs.bevyengine.org](https://dev-docs.bevyengine.org/), +which has the latest API reference built from the repo on every commit made to the `main` branch. ### Writing examples diff --git a/Cargo.toml b/Cargo.toml index ba1947661a0784..f4c6f3f9f90373 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" categories = ["game-engines", "graphics", "gui", "rendering"] description = "A refreshingly simple data-driven game engine and app framework" @@ -26,8 +26,10 @@ members = [ [features] default = [ "animation", + "bevy_asset", "bevy_audio", "bevy_gilrs", + "bevy_scene", "bevy_winit", "render", "png", @@ -53,6 +55,7 @@ render = [ # Optional bevy crates bevy_animation = ["bevy_internal/bevy_animation"] +bevy_asset = ["bevy_internal/bevy_asset"] bevy_audio = ["bevy_internal/bevy_audio"] bevy_core_pipeline = ["bevy_internal/bevy_core_pipeline"] bevy_dynamic_plugin = ["bevy_internal/bevy_dynamic_plugin"] @@ -60,6 +63,7 @@ bevy_gilrs = ["bevy_internal/bevy_gilrs"] bevy_gltf = ["bevy_internal/bevy_gltf"] bevy_pbr = ["bevy_internal/bevy_pbr"] bevy_render = ["bevy_internal/bevy_render"] +bevy_scene = ["bevy_internal/bevy_scene"] bevy_sprite = ["bevy_internal/bevy_sprite"] bevy_text = ["bevy_internal/bevy_text"] bevy_ui = ["bevy_internal/bevy_ui"] @@ -112,18 +116,18 @@ debug_asset_server = ["bevy_internal/debug_asset_server"] animation = ["bevy_internal/animation"] [dependencies] -bevy_dylib = { path = "crates/bevy_dylib", version = "0.8.0-dev", default-features = false, optional = true } -bevy_internal = { path = "crates/bevy_internal", version = "0.8.0-dev", default-features = false } +bevy_dylib = { path = "crates/bevy_dylib", version = "0.9.0-dev", default-features = false, optional = true } +bevy_internal = { path = "crates/bevy_internal", version = "0.9.0-dev", default-features = false } [target.'cfg(target_arch = "wasm32")'.dependencies] -bevy_internal = { path = "crates/bevy_internal", version = "0.8.0-dev", default-features = false, features = [ +bevy_internal = { path = "crates/bevy_internal", version = "0.9.0-dev", default-features = false, features = [ "webgl", ] } [dev-dependencies] anyhow = "1.0.4" rand = "0.8.0" -ron = "0.7.0" +ron = "0.8.0" serde = { version = "1", features = ["derive"] } bytemuck = "1.7" # Needed to poll Task examples @@ -189,11 +193,11 @@ category = "2D Rendering" wasm = true [[example]] -name = "shapes" -path = "examples/2d/shapes.rs" +name = "2d_shapes" +path = "examples/2d/2d_shapes.rs" -[package.metadata.example.shapes] -name = "Shapes" +[package.metadata.example.2d_shapes] +name = "2D Shapes" description = "Renders a rectangle, circle, and hexagon" category = "2D Rendering" wasm = true @@ -271,7 +275,7 @@ wasm = true [[example]] name = "3d_shapes" -path = "examples/3d/shapes.rs" +path = "examples/3d/3d_shapes.rs" [package.metadata.example.3d_shapes] name = "3D Shapes" @@ -389,6 +393,17 @@ description = "Demonstrates how to prevent meshes from casting/receiving shadows category = "3D Rendering" wasm = true +[[example]] +name = "skybox" +path = "examples/3d/skybox.rs" +required-features = ["ktx2", "zstd"] + +[package.metadata.example.skybox] +name = "Skybox" +description = "Load a cubemap texture onto a cube like a skybox and cycle through different compressed texture formats." +category = "3D Rendering" +wasm = false + [[example]] name = "spherical_area_lights" path = "examples/3d/spherical_area_lights.rs" @@ -857,12 +872,12 @@ category = "ECS (Entity Component System)" wasm = false [[example]] -name = "system_chaining" -path = "examples/ecs/system_chaining.rs" +name = "system_piping" +path = "examples/ecs/system_piping.rs" -[package.metadata.example.system_chaining] -name = "System Chaining" -description = "Chain two systems together, specifying a return type in a system (such as `Result`)" +[package.metadata.example.system_piping] +name = "System Piping" +description = "Pipe the output of one system into a second, allowing you to handle any errors gracefully" category = "ECS (Entity Component System)" wasm = false @@ -1254,6 +1269,16 @@ description = "Displays many animated sprites in a grid arrangement with slight category = "Stress Tests" wasm = true +[[example]] +name = "many_buttons" +path = "examples/stress_tests/many_buttons.rs" + +[package.metadata.example.many_buttons] +name = "Many Buttons" +description = "Test rendering of many UI elements" +category = "Stress Tests" +wasm = true + [[example]] name = "many_cubes" path = "examples/stress_tests/many_cubes.rs" @@ -1315,6 +1340,16 @@ description = "A simple way to view glTF models with Bevy. Just run `cargo run - category = "Tools" wasm = true +[[example]] +name = "gamepad_viewer" +path = "examples/tools/gamepad_viewer.rs" + +[package.metadata.example.gamepad_viewer] +name = "Gamepad Viewer" +description = "Shows a visualization of gamepad buttons, sticks, and triggers" +category = "Tools" +wasm = false + # Transforms [[example]] name = "global_vs_local_translation" @@ -1427,6 +1462,16 @@ description = "Illustrates various features of Bevy UI" category = "UI (User Interface)" wasm = true +[[example]] +name = "ui_scaling" +path = "examples/ui/ui_scaling.rs" + +[package.metadata.example.ui_scaling] +name = "UI Scaling" +description = "Illustrates how to scale the UI" +category = "UI (User Interface)" +wasm = true + # Window [[example]] name = "clear_color" @@ -1502,6 +1547,16 @@ path = "tests/window/minimising.rs" [package.metadata.example.minimising] hidden = true +[[example]] +name = "window_resizing" +path = "examples/window/window_resizing.rs" + +[package.metadata.example.window_resizing] +name = "Window Resizing" +description = "Demonstrates resizing and responding to resizing a window" +category = "Window" +wasm = true + # Android [[example]] crate-type = ["cdylib"] @@ -1524,3 +1579,9 @@ target_sdk_version = 31 [package.metadata.android.application] icon = "@mipmap/ic_launcher" label = "Bevy Example" + +[profile.wasm-release] +inherits = "release" +opt-level = "z" +lto = "fat" +codegen-units = 1 diff --git a/README.md b/README.md index a48bac9b88557f..c73b0b6c639ca0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [![Bevy](assets/branding/bevy_logo_light_dark_and_dimmed.svg)](https://bevyengine.org) [![Crates.io](https://img.shields.io/crates/v/bevy.svg)](https://crates.io/crates/bevy) -[![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](./LICENSE) +[![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license) [![Crates.io](https://img.shields.io/crates/d/bevy.svg)](https://crates.io/crates/bevy) [![Rust](https://github.com/bevyengine/bevy/workflows/CI/badge.svg)](https://github.com/bevyengine/bevy/actions) ![iOS cron CI](https://github.com/bevyengine/bevy/workflows/iOS%20cron%20CI/badge.svg) @@ -109,13 +109,31 @@ Additionally, we would like to thank the [Amethyst](https://github.com/amethyst/ ## License -Bevy is free and open source! All code in this repository is dual-licensed under either: +Bevy is free, open source and permissively licensed! +Except where noted (below and/or in individual files), all code in this repository is dual-licensed under either: * MIT License ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)) * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)) -at your option. This means you can select the license you prefer! This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are [very good reasons](https://github.com/bevyengine/bevy/issues/2373) to include both. +at your option. +This means you can select the license you prefer! +This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are [very good reasons](https://github.com/bevyengine/bevy/issues/2373) to include both. -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. +Some of the engine's code carries additional copyright notices and license terms due to their external origins. +These are generally BSD-like, but exact details vary by crate: +If the README of a crate contains a 'License' header (or similar), the additional copyright notices and license terms applicable to that crate will be listed. +The above licensing requirement still applies to contributions to those crates, and sections of those crates will carry those license terms. +The [license](https://doc.rust-lang.org/cargo/reference/manifest.html#the-license-and-license-file-fields) field of each crate will also reflect this. +For example, [`bevy_mikktspace`](./crates/bevy_mikktspace/README.md#license-agreement) has code under the Zlib license (as well as a copyright notice when choosing the MIT license). + +The [assets](assets) included in this repository (for our [examples](./examples/README.md)) typically fall under different open licenses. +These will not be included in your game (unless copied in by you), and they are not distributed in the published bevy crates. +See [CREDITS.md](CREDITS.md) for the details of the licenses of those files. + +### Your contributions + +Unless you explicitly state otherwise, +any contribution intentionally submitted for inclusion in the work by you, +as defined in the Apache-2.0 license, +shall be dual licensed as above, +without any additional terms or conditions. diff --git a/assets/scenes/load_scene_example.scn.ron b/assets/scenes/load_scene_example.scn.ron index 1f9de9dae7da87..696f0c79274f19 100644 --- a/assets/scenes/load_scene_example.scn.ron +++ b/assets/scenes/load_scene_example.scn.ron @@ -1,64 +1,46 @@ -[ - ( - entity: 0, - components: [ - { - "type": "bevy_transform::components::transform::Transform", - "struct": { - "translation": { - "type": "glam::vec3::Vec3", - "value": (0.0, 0.0, 0.0), - }, - "rotation": { - "type": "glam::quat::Quat", - "value": (0.0, 0.0, 0.0, 1.0), - }, - "scale": { - "type": "glam::vec3::Vec3", - "value": (1.0, 1.0, 1.0), - }, +( + entities: [ + ( + entity: 0, + components: [ + { + "bevy_transform::components::transform::Transform": ( + translation: ( + x: 0.0, + y: 0.0, + z: 0.0 + ), + rotation: (0.0, 0.0, 0.0, 1.0), + scale: ( + x: 1.0, + y: 1.0, + z: 1.0 + ), + ), }, - }, - { - "type": "scene::ComponentB", - "struct": { - "value": { - "type": "alloc::string::String", - "value": "hello", - }, + { + "scene::ComponentB": ( + value: "hello", + ), }, - }, - { - "type": "scene::ComponentA", - "struct": { - "x": { - "type": "f32", - "value": 1.0, - }, - "y": { - "type": "f32", - "value": 2.0, - }, + { + "scene::ComponentA": ( + x: 1.0, + y: 2.0, + ), }, - }, - ], - ), - ( - entity: 1, - components: [ - { - "type": "scene::ComponentA", - "struct": { - "x": { - "type": "f32", - "value": 3.0, - }, - "y": { - "type": "f32", - "value": 4.0, - }, + ], + ), + ( + entity: 1, + components: [ + { + "scene::ComponentA": ( + x: 3.0, + y: 4.0, + ), }, - }, - ], - ), -] + ], + ), + ] +) diff --git a/assets/shaders/animate_shader.wgsl b/assets/shaders/animate_shader.wgsl index 947c4a5420aff8..6726fa6263cc6e 100644 --- a/assets/shaders/animate_shader.wgsl +++ b/assets/shaders/animate_shader.wgsl @@ -1,39 +1,7 @@ #import bevy_pbr::mesh_types +// The time since startup data is in the globals binding which is part of the mesh_view_bindings import #import bevy_pbr::mesh_view_bindings -@group(1) @binding(0) -var mesh: Mesh; - -// NOTE: Bindings must come before functions that use them! -#import bevy_pbr::mesh_functions - -struct Vertex { - @location(0) position: vec3, - @location(1) normal: vec3, - @location(2) uv: vec2, -}; - -struct VertexOutput { - @builtin(position) clip_position: vec4, - @location(0) uv: vec2, -}; - -@vertex -fn vertex(vertex: Vertex) -> VertexOutput { - var out: VertexOutput; - out.clip_position = mesh_position_local_to_clip(mesh.model, vec4(vertex.position, 1.0)); - out.uv = vertex.uv; - return out; -} - - -struct Time { - time_since_startup: f32, -}; -@group(2) @binding(0) -var time: Time; - - fn oklab_to_linear_srgb(c: vec3) -> vec3 { let L = c.x; let a = c.y; @@ -43,22 +11,28 @@ fn oklab_to_linear_srgb(c: vec3) -> vec3 { let m_ = L - 0.1055613458 * a - 0.0638541728 * b; let s_ = L - 0.0894841775 * a - 1.2914855480 * b; - let l = l_*l_*l_; - let m = m_*m_*m_; - let s = s_*s_*s_; + let l = l_ * l_ * l_; + let m = m_ * m_ * m_; + let s = s_ * s_ * s_; return vec3( - 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, - -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, - -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s, + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s, ); } +struct FragmentInput { + #import bevy_pbr::mesh_vertex_output +} + @fragment -fn fragment(in: VertexOutput) -> @location(0) vec4 { +fn fragment(in: FragmentInput) -> @location(0) vec4 { let speed = 2.0; - let t_1 = sin(time.time_since_startup * speed) * 0.5 + 0.5; - let t_2 = cos(time.time_since_startup * speed); + // The globals binding contains various global values like time + // which is the time since startup in seconds + let t_1 = sin(globals.time * speed) * 0.5 + 0.5; + let t_2 = cos(globals.time * speed); let distance_to_center = distance(in.uv, vec2(0.5)) * 1.4; diff --git a/assets/shaders/cubemap_unlit.wgsl b/assets/shaders/cubemap_unlit.wgsl new file mode 100644 index 00000000000000..6837384dea3ace --- /dev/null +++ b/assets/shaders/cubemap_unlit.wgsl @@ -0,0 +1,24 @@ +#import bevy_pbr::mesh_view_bindings + +#ifdef CUBEMAP_ARRAY +@group(1) @binding(0) +var base_color_texture: texture_cube_array; +#else +@group(1) @binding(0) +var base_color_texture: texture_cube; +#endif + +@group(1) @binding(1) +var base_color_sampler: sampler; + +@fragment +fn fragment( + #import bevy_pbr::mesh_vertex_output +) -> @location(0) vec4 { + let fragment_position_view_lh = world_position.xyz * vec3(1.0, 1.0, -1.0); + return textureSample( + base_color_texture, + base_color_sampler, + fragment_position_view_lh + ); +} diff --git a/assets/shaders/custom_material_chromatic_aberration.wgsl b/assets/shaders/custom_material_chromatic_aberration.wgsl index e8ccdcfb625133..e09580848f7f8a 100644 --- a/assets/shaders/custom_material_chromatic_aberration.wgsl +++ b/assets/shaders/custom_material_chromatic_aberration.wgsl @@ -1,4 +1,5 @@ #import bevy_pbr::mesh_view_bindings +#import bevy_pbr::utils @group(1) @binding(0) var texture: texture_2d; @@ -12,7 +13,7 @@ fn fragment( #import bevy_sprite::mesh2d_vertex_output ) -> @location(0) vec4 { // Get screen position with coordinates from 0 to 1 - let uv = position.xy / vec2(view.width, view.height); + let uv = coords_to_viewport_uv(position.xy, view.viewport); let offset_strength = 0.02; // Sample each color channel with an arbitrary shift diff --git a/assets/shaders/custom_material_screenspace_texture.wgsl b/assets/shaders/custom_material_screenspace_texture.wgsl index aad35920c093ec..468cc61475a08c 100644 --- a/assets/shaders/custom_material_screenspace_texture.wgsl +++ b/assets/shaders/custom_material_screenspace_texture.wgsl @@ -1,4 +1,5 @@ #import bevy_pbr::mesh_view_bindings +#import bevy_pbr::utils @group(1) @binding(0) var texture: texture_2d; @@ -10,7 +11,7 @@ fn fragment( @builtin(position) position: vec4, #import bevy_pbr::mesh_vertex_output ) -> @location(0) vec4 { - let uv = position.xy / vec2(view.width, view.height); + let uv = coords_to_viewport_uv(position.xy, view.viewport); let color = textureSample(texture, texture_sampler, uv); return color; } diff --git a/assets/shaders/game_of_life.wgsl b/assets/shaders/game_of_life.wgsl index d2a63c975cde42..8858b20751e3c9 100644 --- a/assets/shaders/game_of_life.wgsl +++ b/assets/shaders/game_of_life.wgsl @@ -11,6 +11,7 @@ fn hash(value: u32) -> u32 { state = state * 2654435769u; return state; } + fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } @@ -18,7 +19,6 @@ fn randomFloat(value: u32) -> f32 { @compute @workgroup_size(8, 8, 1) fn init(@builtin(global_invocation_id) invocation_id: vec3, @builtin(num_workgroups) num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); - let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; @@ -27,7 +27,6 @@ fn init(@builtin(global_invocation_id) invocation_id: vec3, @builtin(num_wo textureStore(texture, location, color); } - fn is_alive(location: vec2, offset_x: i32, offset_y: i32) -> i32 { let value: vec4 = textureLoad(texture, location + vec2(offset_x, offset_y)); return i32(value.x); @@ -49,7 +48,6 @@ fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let n_alive = count_alive(location); - let color = vec4(f32(n_alive) / 8.0); var alive: bool; if (n_alive == 3) { @@ -60,8 +58,9 @@ fn update(@builtin(global_invocation_id) invocation_id: vec3) { } else { alive = false; } + let color = vec4(f32(alive)); storageBarrier(); - textureStore(texture, location, vec4(f32(alive))); + textureStore(texture, location, color); } \ No newline at end of file diff --git a/assets/shaders/line_material.wgsl b/assets/shaders/line_material.wgsl index 02f278f60f058b..e47ffe6e16acb3 100644 --- a/assets/shaders/line_material.wgsl +++ b/assets/shaders/line_material.wgsl @@ -1,11 +1,13 @@ struct LineMaterial { - color: vec4; + color: vec4, }; -[[group(1), binding(0)]] +@group(1) @binding(0) var material: LineMaterial; -[[stage(fragment)]] -fn fragment() -> [[location(0)]] vec4 { +@fragment +fn fragment( + #import bevy_pbr::mesh_vertex_output +) -> @location(0) vec4 { return material.color; -} \ No newline at end of file +} diff --git a/assets/textures/Ryfjallet_cubemap.png b/assets/textures/Ryfjallet_cubemap.png new file mode 100644 index 00000000000000..777987b75552ab Binary files /dev/null and b/assets/textures/Ryfjallet_cubemap.png differ diff --git a/assets/textures/Ryfjallet_cubemap_astc4x4.ktx2 b/assets/textures/Ryfjallet_cubemap_astc4x4.ktx2 new file mode 100644 index 00000000000000..78696cadca7eec Binary files /dev/null and b/assets/textures/Ryfjallet_cubemap_astc4x4.ktx2 differ diff --git a/assets/textures/Ryfjallet_cubemap_bc7.ktx2 b/assets/textures/Ryfjallet_cubemap_bc7.ktx2 new file mode 100644 index 00000000000000..17e67c7c9ff8bc Binary files /dev/null and b/assets/textures/Ryfjallet_cubemap_bc7.ktx2 differ diff --git a/assets/textures/Ryfjallet_cubemap_etc2.ktx2 b/assets/textures/Ryfjallet_cubemap_etc2.ktx2 new file mode 100644 index 00000000000000..22a389cfd90e58 Binary files /dev/null and b/assets/textures/Ryfjallet_cubemap_etc2.ktx2 differ diff --git a/assets/textures/Ryfjallet_cubemap_readme.txt b/assets/textures/Ryfjallet_cubemap_readme.txt new file mode 100644 index 00000000000000..81bed0d91d8f3c --- /dev/null +++ b/assets/textures/Ryfjallet_cubemap_readme.txt @@ -0,0 +1,21 @@ +Modifications +============= + +The original work, as attributed below, has been modified as follows using the ImageMagick tool: + +mogrify -resize 256x256 -format png *.jpg +convert posx.png negx.png posy.png negy.png posz.png negz.png -gravity center -append cubemap.png + +Author +====== + +This is the work of Emil Persson, aka Humus. +http://www.humus.name + + + +License +======= + +This work is licensed under a Creative Commons Attribution 3.0 Unported License. +http://creativecommons.org/licenses/by/3.0/ diff --git a/benches/benches/bevy_ecs/components/add_remove_big_sparse_set.rs b/benches/benches/bevy_ecs/components/add_remove_big_sparse_set.rs index db4f83d99edfb5..17a43f1b1cbed4 100644 --- a/benches/benches/bevy_ecs/components/add_remove_big_sparse_set.rs +++ b/benches/benches/bevy_ecs/components/add_remove_big_sparse_set.rs @@ -26,8 +26,7 @@ impl Benchmark { for _ in 0..10_000 { entities.push( world - .spawn() - .insert_bundle(( + .spawn(( A(Mat4::from_scale(Vec3::ONE)), B(Mat4::from_scale(Vec3::ONE)), C(Mat4::from_scale(Vec3::ONE)), diff --git a/benches/benches/bevy_ecs/components/add_remove_big_table.rs b/benches/benches/bevy_ecs/components/add_remove_big_table.rs index 0d2ba46c73a6a3..3407b71639e283 100644 --- a/benches/benches/bevy_ecs/components/add_remove_big_table.rs +++ b/benches/benches/bevy_ecs/components/add_remove_big_table.rs @@ -25,8 +25,7 @@ impl Benchmark { for _ in 0..10_000 { entities.push( world - .spawn() - .insert_bundle(( + .spawn(( A(Mat4::from_scale(Vec3::ONE)), B(Mat4::from_scale(Vec3::ONE)), C(Mat4::from_scale(Vec3::ONE)), diff --git a/benches/benches/bevy_ecs/components/add_remove_sparse_set.rs b/benches/benches/bevy_ecs/components/add_remove_sparse_set.rs index 6cb90f641c7882..07c40b66485a57 100644 --- a/benches/benches/bevy_ecs/components/add_remove_sparse_set.rs +++ b/benches/benches/bevy_ecs/components/add_remove_sparse_set.rs @@ -13,7 +13,7 @@ impl Benchmark { let mut world = World::default(); let mut entities = Vec::with_capacity(10_000); for _ in 0..10_000 { - entities.push(world.spawn().insert(A(0.0)).id()); + entities.push(world.spawn(A(0.0)).id()); } Self(world, entities) diff --git a/benches/benches/bevy_ecs/components/add_remove_table.rs b/benches/benches/bevy_ecs/components/add_remove_table.rs index 67043a5bbd8c20..0d39f3085473ab 100644 --- a/benches/benches/bevy_ecs/components/add_remove_table.rs +++ b/benches/benches/bevy_ecs/components/add_remove_table.rs @@ -12,7 +12,7 @@ impl Benchmark { let mut world = World::default(); let mut entities = Vec::with_capacity(10_000); for _ in 0..10_000 { - entities.push(world.spawn().insert(A(0.0)).id()); + entities.push(world.spawn(A(0.0)).id()); } Self(world, entities) diff --git a/benches/benches/bevy_ecs/components/archetype_updates.rs b/benches/benches/bevy_ecs/components/archetype_updates.rs index 26adacd816a6e5..7574104c38be95 100644 --- a/benches/benches/bevy_ecs/components/archetype_updates.rs +++ b/benches/benches/bevy_ecs/components/archetype_updates.rs @@ -22,7 +22,7 @@ fn setup(system_count: usize) -> (World, SystemStage) { /// create `count` entities with distinct archetypes fn add_archetypes(world: &mut World, count: u16) { for i in 0..count { - let mut e = world.spawn(); + let mut e = world.spawn_empty(); if i & 1 << 0 != 0 { e.insert(A::<0>(1.0)); } diff --git a/benches/benches/bevy_ecs/components/insert_simple_unbatched.rs b/benches/benches/bevy_ecs/components/insert_simple_unbatched.rs index daca82a18c8958..218a3ea78fc34a 100644 --- a/benches/benches/bevy_ecs/components/insert_simple_unbatched.rs +++ b/benches/benches/bevy_ecs/components/insert_simple_unbatched.rs @@ -23,7 +23,7 @@ impl Benchmark { pub fn run(&mut self) { let mut world = World::new(); for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/empty_archetypes.rs b/benches/benches/bevy_ecs/empty_archetypes.rs new file mode 100644 index 00000000000000..0db82700e691ec --- /dev/null +++ b/benches/benches/bevy_ecs/empty_archetypes.rs @@ -0,0 +1,253 @@ +use bevy_ecs::{ + component::Component, + prelude::*, + schedule::{Stage, SystemStage}, + world::World, +}; +use bevy_tasks::{ComputeTaskPool, TaskPool}; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; + +criterion_group!(benches, empty_archetypes); +criterion_main!(benches); + +#[derive(Component)] +struct A(f32); + +fn iter( + query: Query<( + &A<0>, + &A<1>, + &A<2>, + &A<3>, + &A<4>, + &A<5>, + &A<6>, + &A<7>, + &A<8>, + &A<9>, + &A<10>, + &A<11>, + &A<12>, + )>, +) { + for comp in query.iter() { + black_box(comp); + } +} + +fn for_each( + query: Query<( + &A<0>, + &A<1>, + &A<2>, + &A<3>, + &A<4>, + &A<5>, + &A<6>, + &A<7>, + &A<8>, + &A<9>, + &A<10>, + &A<11>, + &A<12>, + )>, +) { + query.for_each(|comp| { + black_box(comp); + }); +} + +fn par_for_each( + task_pool: Res, + query: Query<( + &A<0>, + &A<1>, + &A<2>, + &A<3>, + &A<4>, + &A<5>, + &A<6>, + &A<7>, + &A<8>, + &A<9>, + &A<10>, + &A<11>, + &A<12>, + )>, +) { + query.par_for_each(&*task_pool, 64, |comp| { + black_box(comp); + }); +} + +fn setup(parallel: bool, setup: impl FnOnce(&mut SystemStage)) -> (World, SystemStage) { + let mut world = World::new(); + let mut stage = SystemStage::parallel(); + if parallel { + world.insert_resource(ComputeTaskPool(TaskPool::default())); + } + setup(&mut stage); + (world, stage) +} + +/// create `count` entities with distinct archetypes +fn add_archetypes(world: &mut World, count: u16) { + for i in 0..count { + let mut e = world.spawn(); + e.insert(A::<0>(1.0)); + e.insert(A::<1>(1.0)); + e.insert(A::<2>(1.0)); + e.insert(A::<3>(1.0)); + e.insert(A::<4>(1.0)); + e.insert(A::<5>(1.0)); + e.insert(A::<6>(1.0)); + e.insert(A::<7>(1.0)); + e.insert(A::<8>(1.0)); + e.insert(A::<9>(1.0)); + e.insert(A::<10>(1.0)); + e.insert(A::<11>(1.0)); + e.insert(A::<12>(1.0)); + if i & 1 << 1 != 0 { + e.insert(A::<13>(1.0)); + } + if i & 1 << 2 != 0 { + e.insert(A::<14>(1.0)); + } + if i & 1 << 3 != 0 { + e.insert(A::<15>(1.0)); + } + if i & 1 << 4 != 0 { + e.insert(A::<16>(1.0)); + } + if i & 1 << 5 != 0 { + e.insert(A::<18>(1.0)); + } + if i & 1 << 6 != 0 { + e.insert(A::<19>(1.0)); + } + if i & 1 << 7 != 0 { + e.insert(A::<20>(1.0)); + } + if i & 1 << 8 != 0 { + e.insert(A::<21>(1.0)); + } + if i & 1 << 9 != 0 { + e.insert(A::<22>(1.0)); + } + if i & 1 << 10 != 0 { + e.insert(A::<23>(1.0)); + } + if i & 1 << 11 != 0 { + e.insert(A::<24>(1.0)); + } + if i & 1 << 12 != 0 { + e.insert(A::<25>(1.0)); + } + if i & 1 << 13 != 0 { + e.insert(A::<26>(1.0)); + } + if i & 1 << 14 != 0 { + e.insert(A::<27>(1.0)); + } + if i & 1 << 15 != 0 { + e.insert(A::<28>(1.0)); + } + } +} + +fn empty_archetypes(criterion: &mut Criterion) { + let mut group = criterion.benchmark_group("empty_archetypes"); + for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] { + let (mut world, mut stage) = setup(true, |stage| { + stage.add_system(iter); + }); + add_archetypes(&mut world, archetype_count); + world.clear_entities(); + let mut e = world.spawn(); + e.insert(A::<0>(1.0)); + e.insert(A::<1>(1.0)); + e.insert(A::<2>(1.0)); + e.insert(A::<3>(1.0)); + e.insert(A::<4>(1.0)); + e.insert(A::<5>(1.0)); + e.insert(A::<6>(1.0)); + e.insert(A::<7>(1.0)); + e.insert(A::<8>(1.0)); + e.insert(A::<9>(1.0)); + e.insert(A::<10>(1.0)); + e.insert(A::<11>(1.0)); + e.insert(A::<12>(1.0)); + stage.run(&mut world); + group.bench_with_input( + BenchmarkId::new("iter", archetype_count), + &archetype_count, + |bencher, &_| { + bencher.iter(|| { + stage.run(&mut world); + }) + }, + ); + } + for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] { + let (mut world, mut stage) = setup(true, |stage| { + stage.add_system(for_each); + }); + add_archetypes(&mut world, archetype_count); + world.clear_entities(); + let mut e = world.spawn(); + e.insert(A::<0>(1.0)); + e.insert(A::<1>(1.0)); + e.insert(A::<2>(1.0)); + e.insert(A::<3>(1.0)); + e.insert(A::<4>(1.0)); + e.insert(A::<5>(1.0)); + e.insert(A::<6>(1.0)); + e.insert(A::<7>(1.0)); + e.insert(A::<8>(1.0)); + e.insert(A::<9>(1.0)); + e.insert(A::<10>(1.0)); + e.insert(A::<11>(1.0)); + e.insert(A::<12>(1.0)); + stage.run(&mut world); + group.bench_with_input( + BenchmarkId::new("for_each", archetype_count), + &archetype_count, + |bencher, &_| { + bencher.iter(|| { + stage.run(&mut world); + }) + }, + ); + } + for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] { + let (mut world, mut stage) = setup(true, |stage| { + stage.add_system(par_for_each); + }); + add_archetypes(&mut world, archetype_count); + world.clear_entities(); + let mut e = world.spawn(); + e.insert(A::<0>(1.0)); + e.insert(A::<1>(1.0)); + e.insert(A::<2>(1.0)); + e.insert(A::<3>(1.0)); + e.insert(A::<4>(1.0)); + e.insert(A::<5>(1.0)); + e.insert(A::<6>(1.0)); + e.insert(A::<7>(1.0)); + e.insert(A::<8>(1.0)); + e.insert(A::<9>(1.0)); + e.insert(A::<10>(1.0)); + e.insert(A::<11>(1.0)); + e.insert(A::<12>(1.0)); + stage.run(&mut world); + group.bench_with_input( + BenchmarkId::new("par_for_each", archetype_count), + &archetype_count, + |bencher, &_| { + bencher.iter(|| { + stage.run(&mut world); + }) + }, + ); + } +} diff --git a/benches/benches/bevy_ecs/iteration/iter_frag.rs b/benches/benches/bevy_ecs/iteration/iter_frag.rs index dcc675f6551fab..e2e765c8704145 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..20 { - $world.spawn().insert_bundle(($variants(0.0), Data(1.0))); + $world.spawn(($variants(0.0), Data(1.0))); } )* }; diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_foreach.rs b/benches/benches/bevy_ecs/iteration/iter_frag_foreach.rs index 16cade377f3330..480d6f942d2e94 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_foreach.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_foreach.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..20 { - $world.spawn().insert_bundle(($variants(0.0), Data(1.0))); + $world.spawn(($variants(0.0), Data(1.0))); } )* }; diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_sparse.rs b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_sparse.rs index 4cec9fe20c7397..add30629afe3b9 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_sparse.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_sparse.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..5 { - $world.spawn().insert($variants(0.0)); + $world.spawn($variants(0.0)); } )* }; @@ -21,7 +21,7 @@ impl<'w> Benchmark<'w> { pub fn new() -> Self { let mut world = World::new(); for _ in 0..5 { - world.spawn().insert(Data(1.0)); + world.spawn(Data(1.0)); } create_entities!(world; C00, C01, C02, C03, C04, C05, C06, C07, C08, C09); diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide.rs b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide.rs index e955982cdd4a48..f7807486a14f89 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..20 { - $world.spawn().insert_bundle(( + $world.spawn(( $variants(0.0), Data::<0>(1.0), Data::<1>(1.0), diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide_sparse.rs b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide_sparse.rs index f7d2a066f9fc7a..99ada032f3fd93 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide_sparse.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_foreach_wide_sparse.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..5 { - $world.spawn().insert($variants(0.0)); + $world.spawn($variants(0.0)); } )* }; @@ -36,7 +36,7 @@ impl<'w> Benchmark<'w> { pub fn new() -> Self { let mut world = World::new(); for _ in 0..5 { - world.spawn().insert_bundle(( + world.spawn(( Data::<0>(1.0), Data::<1>(1.0), Data::<2>(1.0), diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_sparse.rs b/benches/benches/bevy_ecs/iteration/iter_frag_sparse.rs index 0778b65429b613..b49e91b8e921d9 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_sparse.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_sparse.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..5 { - $world.spawn().insert($variants(0.0)); + $world.spawn($variants(0.0)); } )* }; @@ -21,7 +21,7 @@ impl<'w> Benchmark<'w> { let mut world = World::new(); for _ in 0..5 { - world.spawn().insert(Data(1.0)); + world.spawn(Data(1.0)); } create_entities!(world; C00, C01, C02, C03, C04, C05, C06, C07, C08, C09); diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_wide.rs b/benches/benches/bevy_ecs/iteration/iter_frag_wide.rs index 024a7bfbdf4509..878535c3fa5ecc 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_wide.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_wide.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..20 { - $world.spawn().insert_bundle(( + $world.spawn(( $variants(0.0), Data::<0>(1.0), Data::<1>(1.0), diff --git a/benches/benches/bevy_ecs/iteration/iter_frag_wide_sparse.rs b/benches/benches/bevy_ecs/iteration/iter_frag_wide_sparse.rs index c3393a240e338e..be6b9ebbf3be52 100644 --- a/benches/benches/bevy_ecs/iteration/iter_frag_wide_sparse.rs +++ b/benches/benches/bevy_ecs/iteration/iter_frag_wide_sparse.rs @@ -6,7 +6,7 @@ macro_rules! create_entities { #[derive(Component)] struct $variants(f32); for _ in 0..5 { - $world.spawn().insert($variants(0.0)); + $world.spawn($variants(0.0)); } )* }; @@ -36,7 +36,7 @@ impl<'w> Benchmark<'w> { let mut world = World::new(); for _ in 0..5 { - world.spawn().insert_bundle(( + world.spawn(( Data::<0>(1.0), Data::<1>(1.0), Data::<2>(1.0), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple.rs b/benches/benches/bevy_ecs/iteration/iter_simple.rs index 5d99e19dba1f0c..41693fbf604d55 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple.rs @@ -21,7 +21,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_foreach.rs b/benches/benches/bevy_ecs/iteration/iter_simple_foreach.rs index ae5b5c87576760..36972562b6128b 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_foreach.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_foreach.rs @@ -21,7 +21,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_sparse_set.rs b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_sparse_set.rs index 98e7ea3f74fa77..24c37debb25628 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_sparse_set.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_sparse_set.rs @@ -23,7 +23,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide.rs b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide.rs index a5a0cea163b891..a6f5902e41b277 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide.rs @@ -35,7 +35,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Rotation(Vec3::X), Position::<0>(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide_sparse_set.rs b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide_sparse_set.rs index d357393c310b61..0b91fe976a02f6 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide_sparse_set.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_foreach_wide_sparse_set.rs @@ -37,7 +37,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Rotation(Vec3::X), Position::<0>(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_sparse_set.rs b/benches/benches/bevy_ecs/iteration/iter_simple_sparse_set.rs index 676d4c4c4eff99..1f3c267d4d50a7 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_sparse_set.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_sparse_set.rs @@ -23,7 +23,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_system.rs b/benches/benches/bevy_ecs/iteration/iter_simple_system.rs index f120b0015f1697..fc90878c587534 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_system.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_system.rs @@ -21,7 +21,7 @@ impl Benchmark { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Position(Vec3::X), Rotation(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_wide.rs b/benches/benches/bevy_ecs/iteration/iter_simple_wide.rs index a182531404f5f4..7e5b763d5275d9 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_wide.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_wide.rs @@ -35,7 +35,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Rotation(Vec3::X), Position::<0>(Vec3::X), diff --git a/benches/benches/bevy_ecs/iteration/iter_simple_wide_sparse_set.rs b/benches/benches/bevy_ecs/iteration/iter_simple_wide_sparse_set.rs index 88de1f225fd94b..8be4a85cccc9fc 100644 --- a/benches/benches/bevy_ecs/iteration/iter_simple_wide_sparse_set.rs +++ b/benches/benches/bevy_ecs/iteration/iter_simple_wide_sparse_set.rs @@ -37,7 +37,7 @@ impl<'w> Benchmark<'w> { // TODO: batch this for _ in 0..10_000 { - world.spawn().insert_bundle(( + world.spawn(( Transform(Mat4::from_scale(Vec3::ONE)), Rotation(Vec3::X), Position::<0>(Vec3::X), diff --git a/benches/benches/bevy_ecs/scheduling/run_criteria.rs b/benches/benches/bevy_ecs/scheduling/run_criteria.rs index 52c5fade22e53b..a301a66417fccb 100644 --- a/benches/benches/bevy_ecs/scheduling/run_criteria.rs +++ b/benches/benches/bevy_ecs/scheduling/run_criteria.rs @@ -1,16 +1,17 @@ -use bevy_ecs::{ - component::Component, - prelude::{ParallelSystemDescriptorCoercion, Res, RunCriteriaDescriptorCoercion}, - schedule::{ShouldRun, Stage, SystemStage}, - system::Query, - world::World, -}; +use bevy_ecs::{prelude::*, schedule::ShouldRun}; use criterion::Criterion; fn run_stage(stage: &mut SystemStage, world: &mut World) { stage.run(world); } +/// Labels for run criteria which either always return yes, or always return no. +#[derive(RunCriteriaLabel)] +enum Always { + Yes, + No, +} + pub fn run_criteria_yes(criterion: &mut Criterion) { let mut world = World::new(); let mut group = criterion.benchmark_group("run_criteria/yes"); @@ -85,14 +86,15 @@ pub fn run_criteria_yes_with_labels(criterion: &mut Criterion) { } for amount in 0..21 { let mut stage = SystemStage::parallel(); - stage.add_system(empty.with_run_criteria(always_yes.label("always yes"))); + + stage.add_system(empty.with_run_criteria(always_yes.label(Always::Yes))); for _ in 0..amount { stage - .add_system(empty.with_run_criteria("always yes")) - .add_system(empty.with_run_criteria("always yes")) - .add_system(empty.with_run_criteria("always yes")) - .add_system(empty.with_run_criteria("always yes")) - .add_system(empty.with_run_criteria("always yes")); + .add_system(empty.with_run_criteria(Always::Yes)) + .add_system(empty.with_run_criteria(Always::Yes)) + .add_system(empty.with_run_criteria(Always::Yes)) + .add_system(empty.with_run_criteria(Always::Yes)) + .add_system(empty.with_run_criteria(Always::Yes)); } // run once to initialize systems run_stage(&mut stage, &mut world); @@ -116,14 +118,15 @@ pub fn run_criteria_no_with_labels(criterion: &mut Criterion) { } for amount in 0..21 { let mut stage = SystemStage::parallel(); - stage.add_system(empty.with_run_criteria(always_no.label("always no"))); + + stage.add_system(empty.with_run_criteria(always_no.label(Always::No))); for _ in 0..amount { stage - .add_system(empty.with_run_criteria("always no")) - .add_system(empty.with_run_criteria("always no")) - .add_system(empty.with_run_criteria("always no")) - .add_system(empty.with_run_criteria("always no")) - .add_system(empty.with_run_criteria("always no")); + .add_system(empty.with_run_criteria(Always::No)) + .add_system(empty.with_run_criteria(Always::No)) + .add_system(empty.with_run_criteria(Always::No)) + .add_system(empty.with_run_criteria(Always::No)) + .add_system(empty.with_run_criteria(Always::No)); } // run once to initialize systems run_stage(&mut stage, &mut world); @@ -136,12 +139,12 @@ pub fn run_criteria_no_with_labels(criterion: &mut Criterion) { group.finish(); } -#[derive(Component)] +#[derive(Component, Resource)] struct TestBool(pub bool); pub fn run_criteria_yes_with_query(criterion: &mut Criterion) { let mut world = World::new(); - world.spawn().insert(TestBool(true)); + world.spawn(TestBool(true)); let mut group = criterion.benchmark_group("run_criteria/yes_using_query"); group.warm_up_time(std::time::Duration::from_millis(500)); group.measurement_time(std::time::Duration::from_secs(3)); diff --git a/benches/benches/bevy_ecs/world/commands.rs b/benches/benches/bevy_ecs/world/commands.rs index 7688ce1d8759d3..41f9bbe29e12aa 100644 --- a/benches/benches/bevy_ecs/world/commands.rs +++ b/benches/benches/bevy_ecs/world/commands.rs @@ -43,7 +43,7 @@ pub fn spawn_commands(criterion: &mut Criterion) { bencher.iter(|| { let mut commands = Commands::new(&mut command_queue, &world); for i in 0..entity_count { - let mut entity = commands.spawn(); + let mut entity = commands.spawn_empty(); if black_box(i % 2 == 0) { entity.insert(A); @@ -87,7 +87,7 @@ pub fn insert_commands(criterion: &mut Criterion) { let mut command_queue = CommandQueue::default(); let mut entities = Vec::new(); for _ in 0..entity_count { - entities.push(world.spawn().id()); + entities.push(world.spawn_empty().id()); } bencher.iter(|| { @@ -95,7 +95,7 @@ pub fn insert_commands(criterion: &mut Criterion) { for entity in &entities { commands .entity(*entity) - .insert_bundle((Matrix::default(), Vec3::default())); + .insert((Matrix::default(), Vec3::default())); } drop(commands); command_queue.apply(&mut world); @@ -106,7 +106,7 @@ pub fn insert_commands(criterion: &mut Criterion) { let mut command_queue = CommandQueue::default(); let mut entities = Vec::new(); for _ in 0..entity_count { - entities.push(world.spawn().id()); + entities.push(world.spawn_empty().id()); } bencher.iter(|| { @@ -238,7 +238,7 @@ pub fn get_or_spawn(criterion: &mut Criterion) { for i in 0..10_000 { commands .get_or_spawn(Entity::from_raw(i)) - .insert_bundle((Matrix::default(), Vec3::default())); + .insert((Matrix::default(), Vec3::default())); } command_queue.apply(&mut world); }); diff --git a/benches/benches/bevy_ecs/world/mod.rs b/benches/benches/bevy_ecs/world/mod.rs index dae5274dc8c25f..8505087e488945 100644 --- a/benches/benches/bevy_ecs/world/mod.rs +++ b/benches/benches/bevy_ecs/world/mod.rs @@ -1,9 +1,11 @@ use criterion::criterion_group; mod commands; +mod spawn; mod world_get; use commands::*; +use spawn::*; use world_get::*; criterion_group!( @@ -21,6 +23,7 @@ criterion_group!( world_query_get, world_query_iter, world_query_for_each, + world_spawn, query_get_component_simple, query_get_component, query_get, diff --git a/benches/benches/bevy_ecs/world/spawn.rs b/benches/benches/bevy_ecs/world/spawn.rs new file mode 100644 index 00000000000000..0404209eaace26 --- /dev/null +++ b/benches/benches/bevy_ecs/world/spawn.rs @@ -0,0 +1,27 @@ +use bevy_ecs::prelude::*; +use criterion::Criterion; +use glam::*; + +#[derive(Component)] +struct A(Mat4); +#[derive(Component)] +struct B(Vec4); + +pub fn world_spawn(criterion: &mut Criterion) { + let mut group = criterion.benchmark_group("spawn_world"); + group.warm_up_time(std::time::Duration::from_millis(500)); + group.measurement_time(std::time::Duration::from_secs(4)); + + for entity_count in (0..5).map(|i| 10_u32.pow(i)) { + group.bench_function(format!("{}_entities", entity_count), |bencher| { + let mut world = World::default(); + bencher.iter(|| { + for _ in 0..entity_count { + world.spawn((A(Mat4::default()), B(Vec4::default()))); + } + }); + }); + } + + group.finish(); +} diff --git a/benches/benches/bevy_ecs/world/world_get.rs b/benches/benches/bevy_ecs/world/world_get.rs index 511864fa27418d..1feb7ca07a3eb0 100644 --- a/benches/benches/bevy_ecs/world/world_get.rs +++ b/benches/benches/bevy_ecs/world/world_get.rs @@ -268,7 +268,7 @@ pub fn query_get_component_simple(criterion: &mut Criterion) { group.bench_function("unchecked", |bencher| { let mut world = World::new(); - let entity = world.spawn().insert(A(0.0)).id(); + let entity = world.spawn(A(0.0)).id(); let mut query = world.query::<&mut A>(); bencher.iter(|| { @@ -281,7 +281,7 @@ pub fn query_get_component_simple(criterion: &mut Criterion) { group.bench_function("system", |bencher| { let mut world = World::new(); - let entity = world.spawn().insert(A(0.0)).id(); + let entity = world.spawn(A(0.0)).id(); fn query_system(In(entity): In, mut query: Query<&mut A>) { for _ in 0..100_000 { let mut a = query.get_mut(entity).unwrap(); diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml index 2ef00a7c53c6c4..1cf3668b094a49 100644 --- a/crates/bevy_animation/Cargo.toml +++ b/crates/bevy_animation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_animation" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides animation functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,13 +10,13 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } -bevy_time = { path = "../bevy_time", version = "0.8.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.9.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.9.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.9.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", features = ["bevy"] } +bevy_time = { path = "../bevy_time", version = "0.9.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.9.0-dev" } diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index ee70d801ef9527..ae3455b09edd17 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -12,7 +12,7 @@ use bevy_ecs::{ entity::Entity, prelude::Component, reflect::ReflectComponent, - schedule::ParallelSystemDescriptorCoercion, + schedule::IntoSystemDescriptor, system::{Query, Res}, }; use bevy_hierarchy::Children; @@ -115,7 +115,7 @@ impl Default for AnimationPlayer { impl AnimationPlayer { /// Start playing an animation, resetting state of the player - pub fn play(&mut self, handle: Handle) -> &mut Self { + pub fn start(&mut self, handle: Handle) -> &mut Self { *self = Self { animation_clip: handle, ..Default::default() @@ -123,6 +123,14 @@ impl AnimationPlayer { self } + /// Start playing an animation, resetting state of the player, unless the requested animation is already playing. + pub fn play(&mut self, handle: Handle) -> &mut Self { + if self.animation_clip != handle || self.is_paused() { + self.start(handle); + } + self + } + /// Set the animation to repeat pub fn repeat(&mut self) -> &mut Self { self.repeat = true; @@ -243,6 +251,7 @@ pub fn animation_player( .keyframe_timestamps .binary_search_by(|probe| probe.partial_cmp(&elapsed).unwrap()) { + Ok(n) if n >= curve.keyframe_timestamps.len() - 1 => continue, // this curve is finished Ok(i) => i, Err(0) => continue, // this curve isn't started yet Err(n) if n > curve.keyframe_timestamps.len() - 1 => continue, // this curve is finished diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index a60532fbb0a561..af2d533437a460 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_app" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides core App functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -16,15 +16,15 @@ bevy_reflect = ["dep:bevy_reflect", "bevy_ecs/bevy_reflect"] [dependencies] # bevy -bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", default-features = false } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", optional = true } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } -bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev", default-features = false } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", optional = true } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } -ron = { version = "0.7.0", optional = true } +ron = { version = "0.8.0", optional = true } +downcast-rs = "1.2.0" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 0e717ca632e269..63ce7d052d16e8 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,8 +1,9 @@ -use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage}; +use crate::{CoreStage, Plugin, PluginGroup, StartupSchedule, StartupStage}; pub use bevy_derive::AppLabel; +use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ event::{Event, Events}, - prelude::{FromWorld, IntoExclusiveSystem}, + prelude::FromWorld, schedule::{ IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet, SystemStage, @@ -15,7 +16,17 @@ use std::fmt::Debug; #[cfg(feature = "trace")] use bevy_utils::tracing::info_span; -bevy_utils::define_label!(AppLabel); +bevy_utils::define_label!( + /// A strongly-typed class of labels used to identify an [`App`]. + AppLabel, + /// A strongly-typed identifier for an [`AppLabel`]. + AppLabelId, +); + +/// The [`Resource`] that stores the [`App`]'s [`TypeRegistry`](bevy_reflect::TypeRegistry). +#[cfg(feature = "bevy_reflect")] +#[derive(Resource, Clone, Deref, DerefMut, Default)] +pub struct AppTypeRegistry(pub bevy_reflect::TypeRegistryArc); #[allow(clippy::needless_doctest_main)] /// A container of app logic and data. @@ -59,21 +70,41 @@ pub struct App { sub_apps: HashMap, } +impl Debug for App { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "App {{ sub_apps: ")?; + f.debug_map() + .entries(self.sub_apps.iter().map(|(k, v)| (k, v))) + .finish()?; + write!(f, "}}") + } +} + /// Each `SubApp` has its own [`Schedule`] and [`World`], enabling a separation of concerns. struct SubApp { app: App, runner: Box, } +impl Debug for SubApp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "SubApp {{ app: ")?; + f.debug_map() + .entries(self.app.sub_apps.iter().map(|(k, v)| (k, v))) + .finish()?; + write!(f, "}}") + } +} + impl Default for App { fn default() -> Self { let mut app = App::empty(); #[cfg(feature = "bevy_reflect")] - app.init_resource::(); + app.init_resource::(); app.add_default_stages() .add_event::() - .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); + .add_system_to_stage(CoreStage::Last, World::clear_trackers); #[cfg(feature = "bevy_ci_testing")] { @@ -140,7 +171,9 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # - /// app.add_stage("my_stage", SystemStage::parallel()); + /// #[derive(StageLabel)] + /// struct MyStage; + /// app.add_stage(MyStage, SystemStage::parallel()); /// ``` pub fn add_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { self.schedule.add_stage(label, stage); @@ -157,7 +190,9 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # - /// app.add_stage_after(CoreStage::Update, "my_stage", SystemStage::parallel()); + /// #[derive(StageLabel)] + /// struct MyStage; + /// app.add_stage_after(CoreStage::Update, MyStage, SystemStage::parallel()); /// ``` pub fn add_stage_after( &mut self, @@ -179,7 +214,9 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # - /// app.add_stage_before(CoreStage::Update, "my_stage", SystemStage::parallel()); + /// #[derive(StageLabel)] + /// struct MyStage; + /// app.add_stage_before(CoreStage::Update, MyStage, SystemStage::parallel()); /// ``` pub fn add_stage_before( &mut self, @@ -201,7 +238,9 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # - /// app.add_startup_stage("my_startup_stage", SystemStage::parallel()); + /// #[derive(StageLabel)] + /// struct MyStartupStage; + /// app.add_startup_stage(MyStartupStage, SystemStage::parallel()); /// ``` pub fn add_startup_stage(&mut self, label: impl StageLabel, stage: S) -> &mut Self { self.schedule @@ -223,9 +262,11 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # + /// #[derive(StageLabel)] + /// struct MyStartupStage; /// app.add_startup_stage_after( /// StartupStage::Startup, - /// "my_startup_stage", + /// MyStartupStage, /// SystemStage::parallel() /// ); /// ``` @@ -254,9 +295,11 @@ impl App { /// # use bevy_ecs::prelude::*; /// # let mut app = App::new(); /// # + /// #[derive(StageLabel)] + /// struct MyStartupStage; /// app.add_startup_stage_before( /// StartupStage::Startup, - /// "my_startup_stage", + /// MyStartupStage, /// SystemStage::parallel() /// ); /// ``` @@ -371,7 +414,7 @@ impl App { use std::any::TypeId; assert!( stage_label.type_id() != TypeId::of::(), - "add systems to a startup stage using App::add_startup_system_to_stage" + "use `add_startup_system_to_stage` instead of `add_system_to_stage` to add a system to a StartupStage" ); self.schedule.add_system_to_stage(stage_label, system); self @@ -406,7 +449,7 @@ impl App { use std::any::TypeId; assert!( stage_label.type_id() != TypeId::of::(), - "add system sets to a startup stage using App::add_startup_system_set_to_stage" + "use `add_startup_system_set_to_stage` instead of `add_system_set_to_stage` to add system sets to a StartupStage" ); self.schedule .add_system_set_to_stage(stage_label, system_set); @@ -642,7 +685,9 @@ impl App { /// /// ``` /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; /// # + /// #[derive(Resource)] /// struct MyCounter { /// counter: usize, /// } @@ -655,15 +700,16 @@ impl App { self } - /// Inserts a non-send [`Resource`] to the app. + /// Inserts a non-send resource to the app. /// /// You usually want to use [`insert_resource`](Self::insert_resource), - /// but there are some special cases when a [`Resource`] cannot be sent across threads. + /// but there are some special cases when a resource cannot be sent across threads. /// /// # Examples /// /// ``` /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; /// # /// struct MyCounter { /// counter: usize, @@ -689,7 +735,9 @@ impl App { /// /// ``` /// # use bevy_app::prelude::*; + /// # use bevy_ecs::prelude::*; /// # + /// #[derive(Resource)] /// struct MyCounter { /// counter: usize, /// } @@ -790,7 +838,8 @@ impl App { /// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`. /// /// To customize the plugins in the group (reorder, disable a plugin, add a new plugin - /// before / after another plugin), see [`add_plugins_with`](Self::add_plugins_with). + /// before / after another plugin), call [`build()`](PluginGroup::build) on the group, + /// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder). /// /// ## Examples /// ``` @@ -799,70 +848,58 @@ impl App { /// App::new() /// .add_plugins(MinimalPlugins); /// ``` - pub fn add_plugins(&mut self, mut group: T) -> &mut Self { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - plugin_group_builder.finish(self); + pub fn add_plugins(&mut self, group: T) -> &mut Self { + let builder = group.build(); + builder.finish(self); self } - /// Adds a group of [`Plugin`]s with an initializer method. + /// Registers the type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource, + /// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive: + /// ```rust,ignore + /// #[derive(Reflect)] + /// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize + /// ``` /// - /// Can be used to add a group of [`Plugin`]s, where the group is modified - /// before insertion into a Bevy application. For example, you can add - /// additional [`Plugin`]s at a specific place in the [`PluginGroup`], or deactivate - /// specific [`Plugin`]s while keeping the rest using a [`PluginGroupBuilder`]. + /// See [`bevy_reflect::TypeRegistry::register`]. + #[cfg(feature = "bevy_reflect")] + pub fn register_type(&mut self) -> &mut Self { + { + let registry = self.world.resource_mut::(); + registry.write().register::(); + } + self + } + + /// Adds the type data `D` to type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource. /// - /// # Examples + /// Most of the time [`App::register_type`] can be used instead to register a type you derived [`Reflect`](bevy_reflect::Reflect) for. + /// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive, + /// or where the type is generic and cannot register e.g. `ReflectSerialize` unconditionally without knowing the specific type parameters, + /// this method can be used to insert additional type data. + /// + /// # Example + /// ```rust + /// use bevy_app::App; + /// use bevy_reflect::{ReflectSerialize, ReflectDeserialize}; /// - /// ``` - /// # use bevy_app::{prelude::*, PluginGroupBuilder}; - /// # - /// # // Dummies created to avoid using `bevy_internal` and `bevy_log`, - /// # // which pulls in too many dependencies and breaks rust-analyzer - /// # pub mod bevy_log { - /// # use bevy_app::prelude::*; - /// # #[derive(Default)] - /// # pub struct LogPlugin; - /// # impl Plugin for LogPlugin{ - /// # fn build(&self, app: &mut App) {} - /// # } - /// # } - /// # struct DefaultPlugins; - /// # impl PluginGroup for DefaultPlugins { - /// # fn build(&mut self, group: &mut PluginGroupBuilder){ - /// # group.add(bevy_log::LogPlugin::default()); - /// # } - /// # } - /// # - /// # struct MyOwnPlugin; - /// # impl Plugin for MyOwnPlugin { - /// # fn build(&self, app: &mut App){;} - /// # } - /// # /// App::new() - /// .add_plugins_with(DefaultPlugins, |group| { - /// group.add_before::(MyOwnPlugin) - /// }); + /// .register_type::>() + /// .register_type_data::, ReflectSerialize>() + /// .register_type_data::, ReflectDeserialize>(); /// ``` - pub fn add_plugins_with(&mut self, mut group: T, func: F) -> &mut Self - where - T: PluginGroup, - F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder, - { - let mut plugin_group_builder = PluginGroupBuilder::default(); - group.build(&mut plugin_group_builder); - func(&mut plugin_group_builder); - plugin_group_builder.finish(self); - self - } - - /// Adds the type `T` to the type registry [`Resource`]. + /// + /// See [`bevy_reflect::TypeRegistry::register_type_data`]. #[cfg(feature = "bevy_reflect")] - pub fn register_type(&mut self) -> &mut Self { + pub fn register_type_data< + T: bevy_reflect::Reflect + 'static, + D: bevy_reflect::TypeData + bevy_reflect::FromType, + >( + &mut self, + ) -> &mut Self { { - let registry = self.world.resource_mut::(); - registry.write().register::(); + let registry = self.world.resource_mut::(); + registry.write().register_type_data::(); } self } diff --git a/crates/bevy_app/src/ci_testing.rs b/crates/bevy_app/src/ci_testing.rs index 66206d91095c35..17d8d929d6a4ce 100644 --- a/crates/bevy_app/src/ci_testing.rs +++ b/crates/bevy_app/src/ci_testing.rs @@ -1,6 +1,7 @@ use crate::{app::AppExit, App}; use serde::Deserialize; +use bevy_ecs::prelude::Resource; use bevy_utils::tracing::info; /// A configuration struct for automated CI testing. @@ -8,7 +9,7 @@ use bevy_utils::tracing::info; /// It gets used when the `bevy_ci_testing` feature is enabled to automatically /// exit a Bevy app when run through the CI. This is needed because otherwise /// Bevy apps would be stuck in the game loop and wouldn't allow the CI to progress. -#[derive(Deserialize)] +#[derive(Deserialize, Resource)] pub struct CiTestingConfig { /// The number of frames after which Bevy should exit. pub exit_after: Option, diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index c0a9c68f79c3fe..d908c420ed0ccd 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -18,6 +18,9 @@ pub use schedule_runner::*; #[allow(missing_docs)] pub mod prelude { + #[cfg(feature = "bevy_reflect")] + #[doc(hidden)] + pub use crate::AppTypeRegistry; #[doc(hidden)] pub use crate::{ app::App, CoreStage, DynamicPlugin, Plugin, PluginGroup, StartupSchedule, StartupStage, diff --git a/crates/bevy_app/src/plugin.rs b/crates/bevy_app/src/plugin.rs index e6e70cf8560296..b768acd0f3dbd2 100644 --- a/crates/bevy_app/src/plugin.rs +++ b/crates/bevy_app/src/plugin.rs @@ -1,3 +1,5 @@ +use downcast_rs::{impl_downcast, Downcast}; + use crate::App; use std::any::Any; @@ -5,7 +7,7 @@ use std::any::Any; /// /// Plugins configure an [`App`]. When an [`App`] registers a plugin, /// the plugin's [`Plugin::build`] function is run. -pub trait Plugin: Any + Send + Sync { +pub trait Plugin: Downcast + Any + Send + Sync { /// Configures the [`App`] to which this plugin is added. fn build(&self, app: &mut App); /// Configures a name for the [`Plugin`] which is primarily used for debugging. @@ -14,6 +16,8 @@ pub trait Plugin: Any + Send + Sync { } } +impl_downcast!(Plugin); + /// A type representing an unsafe function that returns a mutable pointer to a [`Plugin`]. /// It is used for dynamically loading plugins. /// diff --git a/crates/bevy_app/src/plugin_group.rs b/crates/bevy_app/src/plugin_group.rs index bc7f75d7d8113a..91e6773b48d98a 100644 --- a/crates/bevy_app/src/plugin_group.rs +++ b/crates/bevy_app/src/plugin_group.rs @@ -3,9 +3,13 @@ use bevy_utils::{tracing::debug, tracing::warn, HashMap}; use std::any::TypeId; /// Combines multiple [`Plugin`]s into a single unit. -pub trait PluginGroup { +pub trait PluginGroup: Sized { /// Configures the [`Plugin`]s that are to be added. - fn build(&mut self, group: &mut PluginGroupBuilder); + fn build(self) -> PluginGroupBuilder; + /// Sets the value of the given [`Plugin`], if it exists + fn set(self, plugin: T) -> PluginGroupBuilder { + self.build().set(plugin) + } } struct PluginEntry { @@ -13,6 +17,12 @@ struct PluginEntry { enabled: bool, } +impl PluginGroup for PluginGroupBuilder { + fn build(self) -> PluginGroupBuilder { + self + } +} + /// Facilitates the creation and configuration of a [`PluginGroup`]. /// Provides a build ordering to ensure that [`Plugin`]s which produce/require a [`Resource`](bevy_ecs::system::Resource) /// are built before/after dependent/depending [`Plugin`]s. [`Plugin`]s inside the group @@ -25,7 +35,7 @@ pub struct PluginGroupBuilder { impl PluginGroupBuilder { /// Finds the index of a target [`Plugin`]. Panics if the target's [`TypeId`] is not found. - fn index_of(&mut self) -> usize { + fn index_of(&self) -> usize { let index = self .order .iter() @@ -68,9 +78,27 @@ impl PluginGroupBuilder { } } + /// Sets the value of the given [`Plugin`], if it exists. + /// + /// # Panics + /// + /// Panics if the [`Plugin`] does not exist. + pub fn set(mut self, plugin: T) -> Self { + let entry = self.plugins.get_mut(&TypeId::of::()).unwrap_or_else(|| { + panic!( + "{} does not exist in this PluginGroup", + std::any::type_name::(), + ) + }); + entry.plugin = Box::new(plugin); + self + } + /// Adds the plugin [`Plugin`] at the end of this [`PluginGroupBuilder`]. If the plugin was /// already in the group, it is removed from its previous place. - pub fn add(&mut self, plugin: T) -> &mut Self { + // This is not confusing, clippy! + #[allow(clippy::should_implement_trait)] + pub fn add(mut self, plugin: T) -> Self { let target_index = self.order.len(); self.order.push(TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -80,7 +108,7 @@ impl PluginGroupBuilder { /// Adds a [`Plugin`] in this [`PluginGroupBuilder`] before the plugin of type `Target`. /// If the plugin was already the group, it is removed from its previous place. There must /// be a plugin of type `Target` in the group or it will panic. - pub fn add_before(&mut self, plugin: T) -> &mut Self { + pub fn add_before(mut self, plugin: T) -> Self { let target_index = self.index_of::(); self.order.insert(target_index, TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -90,7 +118,7 @@ impl PluginGroupBuilder { /// Adds a [`Plugin`] in this [`PluginGroupBuilder`] after the plugin of type `Target`. /// If the plugin was already the group, it is removed from its previous place. There must /// be a plugin of type `Target` in the group or it will panic. - pub fn add_after(&mut self, plugin: T) -> &mut Self { + pub fn add_after(mut self, plugin: T) -> Self { let target_index = self.index_of::() + 1; self.order.insert(target_index, TypeId::of::()); self.upsert_plugin_state(plugin, target_index); @@ -102,7 +130,7 @@ impl PluginGroupBuilder { /// [`Plugin`]s within a [`PluginGroup`] are enabled by default. This function is used to /// opt back in to a [`Plugin`] after [disabling](Self::disable) it. If there are no plugins /// of type `T` in this group, it will panic. - pub fn enable(&mut self) -> &mut Self { + pub fn enable(mut self) -> Self { let mut plugin_entry = self .plugins .get_mut(&TypeId::of::()) @@ -116,7 +144,7 @@ impl PluginGroupBuilder { /// still be used for ordering with [`add_before`](Self::add_before) or /// [`add_after`](Self::add_after), or it can be [re-enabled](Self::enable). If there are no /// plugins of type `T` in this group, it will panic. - pub fn disable(&mut self) -> &mut Self { + pub fn disable(mut self) -> Self { let mut plugin_entry = self .plugins .get_mut(&TypeId::of::()) @@ -152,7 +180,9 @@ impl PluginGroupBuilder { pub struct NoopPluginGroup; impl PluginGroup for NoopPluginGroup { - fn build(&mut self, _: &mut PluginGroupBuilder) {} + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::default() + } } #[cfg(test)] @@ -177,10 +207,10 @@ mod tests { #[test] fn basic_ordering() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC); assert_eq!( group.order, @@ -194,10 +224,10 @@ mod tests { #[test] fn add_after() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add_after::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add_after::(PluginC); assert_eq!( group.order, @@ -211,10 +241,10 @@ mod tests { #[test] fn add_before() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add_before::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add_before::(PluginC); assert_eq!( group.order, @@ -228,11 +258,11 @@ mod tests { #[test] fn readd() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add(PluginB); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add(PluginB); assert_eq!( group.order, @@ -246,11 +276,11 @@ mod tests { #[test] fn readd_after() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add_after::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add_after::(PluginC); assert_eq!( group.order, @@ -264,11 +294,11 @@ mod tests { #[test] fn readd_before() { - let mut group = PluginGroupBuilder::default(); - group.add(PluginA); - group.add(PluginB); - group.add(PluginC); - group.add_before::(PluginC); + let group = PluginGroupBuilder::default() + .add(PluginA) + .add(PluginB) + .add(PluginC) + .add_before::(PluginC); assert_eq!( group.order, diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index aa63ce1a8b3d01..04535c045dd9d0 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -3,6 +3,7 @@ use crate::{ plugin::Plugin, }; use bevy_ecs::event::{Events, ManualEventReader}; +use bevy_ecs::prelude::Resource; use bevy_utils::{Duration, Instant}; #[cfg(target_arch = "wasm32")] @@ -34,7 +35,7 @@ impl Default for RunMode { /// The configuration information for the [`ScheduleRunnerPlugin`]. /// /// It gets added as a [`Resource`](bevy_ecs::system::Resource) inside of the [`ScheduleRunnerPlugin`]. -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone, Default, Resource)] pub struct ScheduleRunnerSettings { /// Determines whether the [`Schedule`](bevy_ecs::schedule::Schedule) is run once or repeatedly. pub run_mode: RunMode, diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index e16455537f78a3..bc8602b21e9064 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_asset" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides asset functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -15,13 +15,13 @@ debug_asset_server = ["filesystem_watcher"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } -bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } -bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } +bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.9.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", features = ["bevy"] } +bevy_tasks = { path = "../bevy_tasks", version = "0.9.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } # other serde = { version = "1", features = ["derive"] } @@ -30,7 +30,7 @@ anyhow = "1.0.4" thiserror = "1.0" downcast-rs = "1.2.0" fastrand = "1.7.0" -notify = { version = "=5.0.0-pre.11", optional = true } +notify = { version = "5.0.0", optional = true } parking_lot = "0.12.1" [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -40,9 +40,9 @@ wasm-bindgen-futures = "0.4" js-sys = "0.3" [target.'cfg(target_os = "android")'.dependencies] -ndk-glue = { version = "0.5" } +ndk-glue = { version = "0.7" } [dev-dependencies] futures-lite = "1.4.0" tempfile = "3.2.0" -bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.9.0-dev" } diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 249d7c0f6f437b..6e26ad1b23683e 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -5,7 +5,7 @@ use crate::{ RefChange, RefChangeChannel, SourceInfo, SourceMeta, }; use anyhow::Result; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_log::warn; use bevy_tasks::IoTaskPool; use bevy_utils::{Entry, HashMap, Uuid}; @@ -79,9 +79,18 @@ pub struct AssetServerInternal { /// /// The asset server is the primary way of loading assets in bevy. It keeps track of the load state /// of the assets it manages and can even reload them from the filesystem with -/// [`AssetServer::watch_for_changes`]! +/// ``` +/// # use bevy_asset::*; +/// # use bevy_app::*; +/// # let mut app = App::new(); +/// // The asset plugin can be configured to watch for asset changes. +/// app.add_plugin(AssetPlugin { +/// watch_for_changes: true, +/// ..Default::default() +/// }); +/// ``` /// -/// The asset server is a _resource_, so in order to accesss it in a system you need a `Res` +/// The asset server is a _resource_, so in order to access it in a system you need a `Res` /// accessor, like this: /// /// ```rust,no_run @@ -102,7 +111,7 @@ pub struct AssetServerInternal { /// See the [`asset_loading`] example for more information. /// /// [`asset_loading`]: https://github.com/bevyengine/bevy/tree/latest/examples/asset/asset_loading.rs -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct AssetServer { pub(crate) server: Arc, } @@ -169,13 +178,6 @@ impl AssetServer { loaders.push(Arc::new(loader)); } - /// Enable watching of the filesystem for changes, if support is available, starting from after - /// the point of calling this function. - pub fn watch_for_changes(&self) -> Result<(), AssetServerError> { - self.asset_io().watch_for_changes()?; - Ok(()) - } - /// Gets a strong handle for an asset with the provided id. pub fn get_handle>(&self, id: I) -> Handle { let sender = self.server.asset_ref_counter.channel.sender.clone(); @@ -256,7 +258,7 @@ impl AssetServer { /// Gets the overall load state of a group of assets from the provided handles. /// /// This method will only return [`LoadState::Loaded`] if all assets in the - /// group were loaded succesfully. + /// group were loaded successfully. pub fn get_group_load_state(&self, handles: impl IntoIterator) -> LoadState { let mut load_state = LoadState::Loaded; for handle_id in handles { @@ -291,7 +293,7 @@ impl AssetServer { /// `"CARGO_MANIFEST_DIR"` is automatically set to the root folder of your crate (workspace). /// /// The name of the asset folder is set inside the - /// [`AssetServerSettings`](crate::AssetServerSettings) resource. The default name is + /// [`AssetPlugin`](crate::AssetPlugin). The default name is /// `"assets"`. /// /// The asset is loaded asynchronously, and will generally not be available by the time diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 9ba30143dc9644..eb04ceb2cb81b8 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -5,7 +5,7 @@ use crate::{ use bevy_app::App; use bevy_ecs::{ event::{EventWriter, Events}, - system::ResMut, + system::{ResMut, Resource}, world::FromWorld, }; use bevy_utils::HashMap; @@ -33,21 +33,21 @@ impl Debug for AssetEvent { "AssetEvent<{}>::Created", std::any::type_name::() )) - .field("handle", &handle.id) + .field("handle", &handle.id()) .finish(), AssetEvent::Modified { handle } => f .debug_struct(&format!( "AssetEvent<{}>::Modified", std::any::type_name::() )) - .field("handle", &handle.id) + .field("handle", &handle.id()) .finish(), AssetEvent::Removed { handle } => f .debug_struct(&format!( "AssetEvent<{}>::Removed", std::any::type_name::() )) - .field("handle", &handle.id) + .field("handle", &handle.id()) .finish(), } } @@ -66,7 +66,7 @@ impl Debug for AssetEvent { /// Remember, if there are no Strong handles for an asset (i.e. they have all been dropped), the /// asset will unload. Make sure you always have a Strong handle when you want to keep an asset /// loaded! -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct Assets { assets: HashMap, events: Events>, @@ -430,7 +430,7 @@ mod tests { struct MyAsset; let mut app = App::new(); app.add_plugin(bevy_core::CorePlugin) - .add_plugin(crate::AssetPlugin); + .add_plugin(crate::AssetPlugin::default()); app.add_asset::(); let mut assets_before = app.world.resource_mut::>(); let handle = assets_before.add(MyAsset); diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index cdb4cc0010efc3..690dd6769dc7c3 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -6,7 +6,7 @@ use bevy_app::{App, Plugin}; use bevy_ecs::{ event::Events, schedule::SystemLabel, - system::{NonSendMut, Res, ResMut, SystemState}, + system::{NonSendMut, Res, ResMut, Resource, SystemState}, }; use bevy_tasks::{IoTaskPool, TaskPoolBuilder}; use bevy_utils::HashMap; @@ -16,8 +16,7 @@ use std::{ }; use crate::{ - Asset, AssetEvent, AssetPlugin, AssetServer, AssetServerSettings, Assets, FileAssetIo, Handle, - HandleUntyped, + Asset, AssetEvent, AssetPlugin, AssetServer, Assets, FileAssetIo, Handle, HandleUntyped, }; /// A helper [`App`] used for hot reloading internal assets, which are compiled-in to Bevy plugins. @@ -52,6 +51,7 @@ pub struct DebugAssetServerPlugin; /// A collection that maps internal assets in a [`DebugAssetApp`]'s asset server to their mirrors in /// the main [`App`]. +#[derive(Resource)] pub struct HandleMap { /// The collection of asset handles. pub handles: HashMap, Handle>, @@ -74,12 +74,10 @@ impl Plugin for DebugAssetServerPlugin { .build() }); let mut debug_asset_app = App::new(); - debug_asset_app - .insert_resource(AssetServerSettings { - asset_folder: "crates".to_string(), - watch_for_changes: true, - }) - .add_plugin(AssetPlugin); + debug_asset_app.add_plugin(AssetPlugin { + asset_folder: "crates".to_string(), + watch_for_changes: true, + }); app.insert_non_send_resource(DebugAssetApp(debug_asset_app)); app.add_system(run_debug_asset_app); } @@ -116,7 +114,7 @@ pub(crate) fn sync_debug_assets( /// Uses the return type of the given loader to register the given handle with the appropriate type /// and load the asset with the given `path` and parent `file_path`. /// -/// If this feels a bit odd ... thats because it is. This was built to improve the UX of the +/// If this feels a bit odd ... that's because it is. This was built to improve the UX of the /// `load_internal_asset` macro. pub fn register_handle_with_loader( _loader: fn(&'static str) -> A, diff --git a/crates/bevy_asset/src/filesystem_watcher.rs b/crates/bevy_asset/src/filesystem_watcher.rs index 5ee499e80e3ed6..ace2500cd5b8ff 100644 --- a/crates/bevy_asset/src/filesystem_watcher.rs +++ b/crates/bevy_asset/src/filesystem_watcher.rs @@ -1,5 +1,5 @@ use crossbeam_channel::Receiver; -use notify::{Event, RecommendedWatcher, RecursiveMode, Result, Watcher}; +use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Result, Watcher}; use std::path::Path; /// Watches for changes to files on the local filesystem. @@ -14,9 +14,12 @@ pub struct FilesystemWatcher { impl Default for FilesystemWatcher { fn default() -> Self { let (sender, receiver) = crossbeam_channel::unbounded(); - let watcher: RecommendedWatcher = RecommendedWatcher::new(move |res| { - sender.send(res).expect("Watch event send failure."); - }) + let watcher: RecommendedWatcher = RecommendedWatcher::new( + move |res| { + sender.send(res).expect("Watch event send failure."); + }, + Config::default(), + ) .expect("Failed to create filesystem watcher."); FilesystemWatcher { watcher, receiver } } diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index abd6e13a98b792..c374c6b070ace7 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -10,7 +10,9 @@ use crate::{ Asset, Assets, }; use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize, ReflectSerialize}; +use bevy_reflect::{ + std_traits::ReflectDefault, FromReflect, Reflect, ReflectDeserialize, ReflectSerialize, +}; use bevy_utils::Uuid; use crossbeam_channel::{Receiver, Sender}; use serde::{Deserialize, Serialize}; @@ -100,13 +102,12 @@ impl HandleId { /// collisions no longer being detected for that entity. /// #[derive(Component, Reflect, FromReflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Handle where T: Asset, { - /// The ID of the asset as contained within its respective [`Assets`] collection - pub id: HandleId, + id: HandleId, #[reflect(ignore)] handle_type: HandleType, #[reflect(ignore)] @@ -151,6 +152,12 @@ impl Handle { } } + /// The ID of the asset as contained within its respective [`Assets`] collection. + #[inline] + pub fn id(&self) -> HandleId { + self.id + } + /// Recasts this handle as a weak handle of an Asset `U`. pub fn as_weak(&self) -> Handle { Handle { diff --git a/crates/bevy_asset/src/io/android_asset_io.rs b/crates/bevy_asset/src/io/android_asset_io.rs index bbdf94d6a9c806..4b5f41b140fc2c 100644 --- a/crates/bevy_asset/src/io/android_asset_io.rs +++ b/crates/bevy_asset/src/io/android_asset_io.rs @@ -12,7 +12,7 @@ use std::{ /// Implementation details: /// /// - `load_path` uses the [AssetManager] to load files. -/// - `read_directory` always returns an empty itrator. +/// - `read_directory` always returns an empty iterator. /// - `get_metadata` will probably return an error. /// - Watching for changes is not supported. The watcher methods will do nothing. /// diff --git a/crates/bevy_asset/src/io/wasm_asset_io.rs b/crates/bevy_asset/src/io/wasm_asset_io.rs index 91fe067128c683..1cf8d3b2715ea9 100644 --- a/crates/bevy_asset/src/io/wasm_asset_io.rs +++ b/crates/bevy_asset/src/io/wasm_asset_io.rs @@ -25,6 +25,7 @@ pub struct WasmAssetIo { } impl WasmAssetIo { + /// Creates a new `WasmAssetIo`. The path provided will be used to build URLs to query for assets. pub fn new>(path: P) -> Self { WasmAssetIo { root_path: path.as_ref().to_owned(), @@ -51,6 +52,7 @@ impl AssetIo for WasmAssetIo { &self, _path: &Path, ) -> Result>, AssetIoError> { + bevy_log::warn!("Loading folders is not supported in WASM"); Ok(Box::new(std::iter::empty::())) } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index f70bc5c1f4fd42..ff125d3abd275c 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -29,9 +29,12 @@ mod path; /// The `bevy_asset` prelude. pub mod prelude { #[doc(hidden)] - pub use crate::{AddAsset, AssetEvent, AssetServer, Assets, Handle, HandleUntyped}; + pub use crate::{ + AddAsset, AssetEvent, AssetPlugin, AssetServer, Assets, Handle, HandleUntyped, + }; } +pub use anyhow::Error; pub use asset_server::*; pub use assets::*; pub use bevy_utils::BoxedFuture; @@ -57,11 +60,7 @@ pub enum AssetStage { /// /// Assets are typed collections with change tracking, which are added as App Resources. Examples of /// assets: textures, sounds, 3d models, maps, scenes -#[derive(Default)] -pub struct AssetPlugin; - -/// [`AssetServer`] settings. -pub struct AssetServerSettings { +pub struct AssetPlugin { /// The base folder where assets are loaded from, relative to the executable. pub asset_folder: String, /// Whether to watch for changes in asset files. Requires the `filesystem_watcher` feature, @@ -69,7 +68,7 @@ pub struct AssetServerSettings { pub watch_for_changes: bool, } -impl Default for AssetServerSettings { +impl Default for AssetPlugin { fn default() -> Self { Self { asset_folder: "assets".to_string(), @@ -78,29 +77,27 @@ impl Default for AssetServerSettings { } } -/// Creates an instance of the platform's default `AssetIo`. -/// -/// This is useful when providing a custom `AssetIo` instance that needs to -/// delegate to the default `AssetIo` for the platform. -pub fn create_platform_default_asset_io(app: &mut App) -> Box { - let settings = app - .world - .get_resource_or_insert_with(AssetServerSettings::default); - - #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] - let source = FileAssetIo::new(&settings.asset_folder, settings.watch_for_changes); - #[cfg(target_arch = "wasm32")] - let source = WasmAssetIo::new(&settings.asset_folder); - #[cfg(target_os = "android")] - let source = AndroidAssetIo::new(&settings.asset_folder); +impl AssetPlugin { + /// Creates an instance of the platform's default `AssetIo`. + /// + /// This is useful when providing a custom `AssetIo` instance that needs to + /// delegate to the default `AssetIo` for the platform. + pub fn create_platform_default_asset_io(&self) -> Box { + #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] + let source = FileAssetIo::new(&self.asset_folder, self.watch_for_changes); + #[cfg(target_arch = "wasm32")] + let source = WasmAssetIo::new(&self.asset_folder); + #[cfg(target_os = "android")] + let source = AndroidAssetIo::new(&self.asset_folder); - Box::new(source) + Box::new(source) + } } impl Plugin for AssetPlugin { fn build(&self, app: &mut App) { if !app.world.contains_resource::() { - let source = create_platform_default_asset_io(app); + let source = self.create_platform_default_asset_io(); let asset_server = AssetServer::with_boxed_io(source); app.insert_resource(asset_server); } diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 3d420e8f834299..f6a5153b490d95 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -2,6 +2,7 @@ use crate::{ path::AssetPath, AssetIo, AssetIoError, AssetMeta, AssetServer, Assets, Handle, HandleId, RefChangeChannel, }; +use anyhow::Error; use anyhow::Result; use bevy_ecs::system::{Res, ResMut}; use bevy_reflect::{TypeUuid, TypeUuidDynamic}; @@ -20,7 +21,7 @@ pub trait AssetLoader: Send + Sync + 'static { &'a self, bytes: &'a [u8], load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result<(), anyhow::Error>>; + ) -> BoxedFuture<'a, Result<(), Error>>; /// Returns a list of extensions supported by this asset loader, without the preceding dot. fn extensions(&self) -> &[&str]; diff --git a/crates/bevy_asset/src/path.rs b/crates/bevy_asset/src/path.rs index d47bca18e7617b..e9150c63a88349 100644 --- a/crates/bevy_asset/src/path.rs +++ b/crates/bevy_asset/src/path.rs @@ -8,7 +8,7 @@ use std::{ }; /// Represents a path to an asset in the file system. -#[derive(Debug, Hash, Clone, Serialize, Deserialize)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)] pub struct AssetPath<'a> { path: Cow<'a, Path>, label: Option>, @@ -154,7 +154,7 @@ impl<'a, 'b> From<&'a AssetPath<'b>> for AssetPathId { impl<'a> From<&'a str> for AssetPath<'a> { fn from(asset_path: &'a str) -> Self { - let mut parts = asset_path.split('#'); + let mut parts = asset_path.splitn(2, '#'); let path = Path::new(parts.next().expect("Path must be set.")); let label = parts.next(); AssetPath { @@ -187,3 +187,15 @@ impl<'a> From for AssetPath<'a> { } } } + +impl<'a> From for AssetPath<'a> { + fn from(asset_path: String) -> Self { + let mut parts = asset_path.splitn(2, '#'); + let path = PathBuf::from(parts.next().expect("Path must be set.")); + let label = parts.next().map(String::from); + AssetPath { + path: Cow::Owned(path), + label: label.map(Cow::Owned), + } + } +} diff --git a/crates/bevy_audio/Cargo.toml b/crates/bevy_audio/Cargo.toml index b8d1148c8fc6ac..495091215275c8 100644 --- a/crates/bevy_audio/Cargo.toml +++ b/crates/bevy_audio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_audio" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides audio functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,19 +10,19 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", features = ["bevy"] } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } # other anyhow = "1.0.4" -rodio = { version = "0.15", default-features = false } +rodio = { version = "0.16", default-features = false } parking_lot = "0.12.1" [target.'cfg(target_arch = "wasm32")'.dependencies] -rodio = { version = "0.15", default-features = false, features = ["wasm-bindgen"] } +rodio = { version = "0.16", default-features = false, features = ["wasm-bindgen"] } [features] diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index a7c3a614ba66bc..d7ac8d615795b4 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -1,9 +1,10 @@ use crate::{AudioSink, AudioSource, Decodable}; use bevy_asset::{Asset, Handle, HandleId}; +use bevy_ecs::system::Resource; use parking_lot::RwLock; use std::{collections::VecDeque, fmt}; -/// Use this resource to play audio +/// Use this [`Resource`] to play audio. /// /// ``` /// # use bevy_ecs::system::Res; @@ -13,6 +14,7 @@ use std::{collections::VecDeque, fmt}; /// audio.play(asset_server.load("my_sound.ogg")); /// } /// ``` +#[derive(Resource)] pub struct Audio where Source: Asset + Decodable, diff --git a/crates/bevy_audio/src/audio_source.rs b/crates/bevy_audio/src/audio_source.rs index 9cdb3ab3f7792f..217c9aa8683500 100644 --- a/crates/bevy_audio/src/audio_source.rs +++ b/crates/bevy_audio/src/audio_source.rs @@ -57,8 +57,8 @@ impl AssetLoader for AudioLoader { /// A type implementing this trait can be decoded as a rodio source pub trait Decodable: Send + Sync + 'static { - /// The decoder that can decode the implemeting type - type Decoder: rodio::Source + Send + Sync + Iterator; + /// The decoder that can decode the implementing type + type Decoder: rodio::Source + Send + Iterator; /// A single value given by the decoder type DecoderItem: rodio::Sample + Send + Sync; diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index c4f2390ebf4eb7..8ad4f95217b51f 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -8,7 +8,7 @@ //! fn main() { //! App::new() //! .add_plugins(MinimalPlugins) -//! .add_plugin(AssetPlugin) +//! .add_plugin(AssetPlugin::default()) //! .add_plugin(AudioPlugin) //! .add_startup_system(play_background_audio) //! .run(); diff --git a/crates/bevy_core/Cargo.toml b/crates/bevy_core/Cargo.toml index 7035d2fbc22350..5c26103cb7a828 100644 --- a/crates/bevy_core/Cargo.toml +++ b/crates/bevy_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_core" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides core functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -11,12 +11,15 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev", features = ["bevy_reflect"] } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", features = ["bevy_reflect"] } -bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } -bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev", features = ["bevy_reflect"] } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev", features = ["bevy_reflect"] } +bevy_math = { path = "../bevy_math", version = "0.9.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", features = ["bevy"] } +bevy_tasks = { path = "../bevy_tasks", version = "0.9.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } # other bytemuck = "1.5" + +[dev-dependencies] +crossbeam-channel = "0.5.0" diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 41b8e02d4935ef..89ff2ca9deb012 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -4,6 +4,7 @@ mod name; mod task_pool_options; +use bevy_ecs::system::Resource; pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable}; pub use name::*; pub use task_pool_options::*; @@ -16,9 +17,16 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::entity::Entity; -use bevy_utils::HashSet; +use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; +use bevy_utils::{Duration, HashSet, Instant}; +use std::borrow::Cow; use std::ops::Range; +#[cfg(not(target_arch = "wasm32"))] +use bevy_ecs::schedule::IntoSystemDescriptor; +#[cfg(not(target_arch = "wasm32"))] +use bevy_tasks::tick_global_task_pools_on_main_thread; + /// Adds core functionality to Apps. #[derive(Default)] pub struct CorePlugin; @@ -32,10 +40,23 @@ impl Plugin for CorePlugin { .unwrap_or_default() .create_default_pools(); + #[cfg(not(target_arch = "wasm32"))] + app.add_system_to_stage( + bevy_app::CoreStage::Last, + tick_global_task_pools_on_main_thread.at_end(), + ); + app.register_type::().register_type::(); + app.register_type::() + .register_type::() + .register_type::>() + .register_type_data::, ReflectSerialize>() + .register_type_data::, ReflectDeserialize>(); register_rust_types(app); register_math_types(app); + + app.init_resource::(); } } @@ -43,7 +64,10 @@ fn register_rust_types(app: &mut App) { app.register_type::>() .register_type::() .register_type::>() - .register_type::>(); + .register_type::>() + .register_type::>() + .register_type::() + .register_type::(); } fn register_math_types(app: &mut App) { @@ -53,11 +77,74 @@ fn register_math_types(app: &mut App) { .register_type::() .register_type::() .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() .register_type::() .register_type::() + .register_type::() .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() .register_type::() .register_type::() + .register_type::() .register_type::() + .register_type::() .register_type::(); } + +/// Keeps a count of rendered frames since the start of the app +/// +/// Wraps to 0 when it reaches the maximum u32 value +#[derive(Default, Resource, Clone, Copy)] +pub struct FrameCount(pub u32); + +#[cfg(test)] +mod tests { + use super::*; + use bevy_tasks::prelude::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool}; + + #[test] + fn runs_spawn_local_tasks() { + let mut app = App::new(); + app.add_plugin(CorePlugin); + + let (async_tx, async_rx) = crossbeam_channel::unbounded(); + AsyncComputeTaskPool::get() + .spawn_local(async move { + async_tx.send(()).unwrap(); + }) + .detach(); + + let (compute_tx, compute_rx) = crossbeam_channel::unbounded(); + ComputeTaskPool::get() + .spawn_local(async move { + compute_tx.send(()).unwrap(); + }) + .detach(); + + let (io_tx, io_rx) = crossbeam_channel::unbounded(); + IoTaskPool::get() + .spawn_local(async move { + io_tx.send(()).unwrap(); + }) + .detach(); + + app.run(); + + async_rx.try_recv().unwrap(); + compute_rx.try_recv().unwrap(); + io_rx.try_recv().unwrap(); + } +} diff --git a/crates/bevy_core/src/task_pool_options.rs b/crates/bevy_core/src/task_pool_options.rs index 152489b7cf7aea..43779a072c0a88 100644 --- a/crates/bevy_core/src/task_pool_options.rs +++ b/crates/bevy_core/src/task_pool_options.rs @@ -1,3 +1,4 @@ +use bevy_ecs::prelude::Resource; use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder}; use bevy_utils::tracing::trace; @@ -33,12 +34,12 @@ impl TaskPoolThreadAssignmentPolicy { /// Helper for configuring and creating the default task pools. For end-users who want full control, /// insert the default task pools into the resource map manually. If the pools are already inserted, /// this helper will do nothing. -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct DefaultTaskPoolOptions { /// If the number of physical cores is less than min_total_threads, force using /// min_total_threads pub min_total_threads: usize, - /// If the number of physical cores is grater than max_total_threads, force using + /// If the number of physical cores is greater than max_total_threads, force using /// max_total_threads pub max_total_threads: usize, @@ -93,8 +94,8 @@ impl DefaultTaskPoolOptions { /// Inserts the default thread pools into the given resource map based on the configured values pub fn create_default_pools(&self) { - let total_threads = - bevy_tasks::logical_core_count().clamp(self.min_total_threads, self.max_total_threads); + let total_threads = bevy_tasks::available_parallelism() + .clamp(self.min_total_threads, self.max_total_threads); trace!("Assigning {} cores to default task pools", total_threads); let mut remaining_threads = total_threads; diff --git a/crates/bevy_core_pipeline/Cargo.toml b/crates/bevy_core_pipeline/Cargo.toml index 26c8ffee151160..42612f77bf0c33 100644 --- a/crates/bevy_core_pipeline/Cargo.toml +++ b/crates/bevy_core_pipeline/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_core_pipeline" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" authors = [ "Bevy Contributors ", @@ -18,14 +18,13 @@ webgl = [] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } -bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev" } -bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev" } +bevy_render = { path = "../bevy_render", version = "0.9.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } serde = { version = "1", features = ["derive"] } radsort = "0.1" diff --git a/crates/bevy_core_pipeline/src/clear_color.rs b/crates/bevy_core_pipeline/src/clear_color.rs index 6160f2256f039b..50861e1bebb1f8 100644 --- a/crates/bevy_core_pipeline/src/clear_color.rs +++ b/crates/bevy_core_pipeline/src/clear_color.rs @@ -5,7 +5,7 @@ use bevy_render::{color::Color, extract_resource::ExtractResource}; use serde::{Deserialize, Serialize}; #[derive(Reflect, Serialize, Deserialize, Clone, Debug, Default)] -#[reflect_value(Serialize, Deserialize)] +#[reflect(Serialize, Deserialize)] pub enum ClearColorConfig { #[default] Default, @@ -13,11 +13,11 @@ pub enum ClearColorConfig { None, } -/// When used as a resource, sets the color that is used to clear the screen between frames. +/// A [`Resource`] that stores the color that is used to clear the screen between frames. /// -/// This color appears as the "background" color for simple apps, when -/// there are portions of the screen with nothing rendered. -#[derive(Component, Clone, Debug, Deref, DerefMut, ExtractResource, Reflect)] +/// This color appears as the "background" color for simple apps, +/// when there are portions of the screen with nothing rendered. +#[derive(Resource, Clone, Debug, Deref, DerefMut, ExtractResource, Reflect)] #[reflect(Resource)] pub struct ClearColor(pub Color); diff --git a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs index e389ca68331d74..b94b59a0b65254 100644 --- a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs +++ b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs @@ -2,9 +2,7 @@ use crate::clear_color::ClearColorConfig; use bevy_ecs::{prelude::*, query::QueryItem}; use bevy_reflect::Reflect; use bevy_render::{ - camera::{ - Camera, CameraProjection, CameraRenderGraph, DepthCalculation, OrthographicProjection, - }, + camera::{Camera, CameraProjection, CameraRenderGraph, OrthographicProjection}, extract_component::ExtractComponent, primitives::Frustum, view::VisibleEntities, @@ -56,7 +54,6 @@ impl Camera2dBundle { // the camera's translation by far and use a right handed coordinate system let projection = OrthographicProjection { far, - depth_calculation: DepthCalculation::ZDifference, ..Default::default() }; let transform = Transform::from_xyz(0.0, 0.0, far - 0.1); diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index 69db8d4ad45609..cc0ddc184746bc 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -46,7 +46,10 @@ impl Plugin for Core2dPlugin { .init_resource::>() .add_system_to_stage(RenderStage::Extract, extract_core_2d_camera_phases) .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::) - .add_system_to_stage(RenderStage::PhaseSort, batch_phase_system::); + .add_system_to_stage( + RenderStage::PhaseSort, + batch_phase_system::.after(sort_phase_system::), + ); let pass_node_2d = MainPass2dNode::new(&mut render_app.world); let mut graph = render_app.world.resource_mut::(); @@ -125,7 +128,7 @@ pub fn extract_core_2d_camera_phases( mut commands: Commands, cameras_2d: Extract>>, ) { - for (entity, camera) in cameras_2d.iter() { + for (entity, camera) in &cameras_2d { if camera.is_active { commands .get_or_spawn(entity) diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index bca403cc0303c9..ce91c2d2e04a8a 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -23,7 +23,7 @@ pub struct Camera3d { /// The depth clear operation to perform for the main 3d pass. #[derive(Reflect, Serialize, Deserialize, Clone, Debug)] -#[reflect_value(Serialize, Deserialize)] +#[reflect(Serialize, Deserialize)] pub enum Camera3dDepthLoadOp { /// Clear with a specified value. /// Note that 0.0 is the far plane due to bevy's use of reverse-z projections. diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index c69e8104dc15fd..4faa8ea1ca227a 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -43,6 +43,7 @@ pub struct Core3dPlugin; impl Plugin for Core3dPlugin { fn build(&self, app: &mut App) { app.register_type::() + .register_type::() .add_plugin(ExtractComponentPlugin::::default()); let render_app = match app.get_sub_app_mut(RenderApp) { @@ -210,9 +211,9 @@ pub fn extract_core_3d_camera_phases( mut commands: Commands, cameras_3d: Extract>>, ) { - for (entity, camera) in cameras_3d.iter() { + for (entity, camera) in &cameras_3d { if camera.is_active { - commands.get_or_spawn(entity).insert_bundle(( + commands.get_or_spawn(entity).insert(( RenderPhase::::default(), RenderPhase::::default(), RenderPhase::::default(), diff --git a/crates/bevy_core_pipeline/src/lib.rs b/crates/bevy_core_pipeline/src/lib.rs index 28304608e76615..0cc46286148d81 100644 --- a/crates/bevy_core_pipeline/src/lib.rs +++ b/crates/bevy_core_pipeline/src/lib.rs @@ -11,7 +11,11 @@ pub mod prelude { }; } -use crate::{clear_color::ClearColor, core_2d::Core2dPlugin, core_3d::Core3dPlugin}; +use crate::{ + clear_color::{ClearColor, ClearColorConfig}, + core_2d::Core2dPlugin, + core_3d::Core3dPlugin, +}; use bevy_app::{App, Plugin}; use bevy_render::extract_resource::ExtractResourcePlugin; @@ -21,6 +25,7 @@ pub struct CorePipelinePlugin; impl Plugin for CorePipelinePlugin { fn build(&self, app: &mut App) { app.register_type::() + .register_type::() .init_resource::() .add_plugin(ExtractResourcePlugin::::default()) .add_plugin(Core2dPlugin) diff --git a/crates/bevy_derive/Cargo.toml b/crates/bevy_derive/Cargo.toml index ea2fd068c17517..267da668f6700c 100644 --- a/crates/bevy_derive/Cargo.toml +++ b/crates/bevy_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_derive" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides derive implementations for Bevy Engine" homepage = "https://bevyengine.org" @@ -12,7 +12,7 @@ keywords = ["bevy"] proc-macro = true [dependencies] -bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.8.0-dev" } +bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.9.0-dev" } quote = "1.0" syn = { version = "1.0", features = ["full"] } diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index 3c43776ef99619..e2088cfe04ec1a 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -80,10 +80,14 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream { enum_variant_meta::derive_enum_variant_meta(input) } -#[proc_macro_derive(AppLabel)] +/// Generates an impl of the `AppLabel` trait. +/// +/// This works only for unit structs, or enums with only unit variants. +/// You may force a struct or variant to behave as if it were fieldless with `#[app_label(ignore_fields)]`. +#[proc_macro_derive(AppLabel, attributes(app_label))] pub fn derive_app_label(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); let mut trait_path = BevyManifest::default().get_path("bevy_app"); trait_path.segments.push(format_ident!("AppLabel").into()); - derive_label(input, &trait_path) + derive_label(input, &trait_path, "app_label") } diff --git a/crates/bevy_diagnostic/Cargo.toml b/crates/bevy_diagnostic/Cargo.toml index 5bdd7236e490bc..85ac1a5b08640a 100644 --- a/crates/bevy_diagnostic/Cargo.toml +++ b/crates/bevy_diagnostic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_diagnostic" -version = "0.8.0-dev" +version = "0.9.0-dev" edition = "2021" description = "Provides diagnostic functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -11,8 +11,9 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } -bevy_time = { path = "../bevy_time", version = "0.8.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.9.0-dev" } +bevy_time = { path = "../bevy_time", version = "0.9.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.9.0-dev" } diff --git a/crates/bevy_diagnostic/src/diagnostic.rs b/crates/bevy_diagnostic/src/diagnostic.rs index f53e04307e869d..7d947359db3c36 100644 --- a/crates/bevy_diagnostic/src/diagnostic.rs +++ b/crates/bevy_diagnostic/src/diagnostic.rs @@ -1,3 +1,4 @@ +use bevy_ecs::system::Resource; use bevy_log::warn; use bevy_utils::{Duration, Instant, StableHashMap, Uuid}; use std::{borrow::Cow, collections::VecDeque}; @@ -36,6 +37,8 @@ pub struct Diagnostic { pub suffix: Cow<'static, str>, history: VecDeque, sum: f64, + ema: f64, + ema_smoothing_factor: f64, max_history_length: usize, pub is_enabled: bool, } @@ -44,6 +47,15 @@ impl Diagnostic { /// Add a new value as a [`DiagnosticMeasurement`]. Its timestamp will be [`Instant::now`]. pub fn add_measurement(&mut self, value: f64) { let time = Instant::now(); + + if let Some(previous) = self.measurement() { + let delta = (time - previous.time).as_secs_f64(); + let alpha = (delta / self.ema_smoothing_factor).clamp(0.0, 1.0); + self.ema += alpha * (value - self.ema); + } else { + self.ema = value; + } + if self.max_history_length > 1 { if self.history.len() == self.max_history_length { if let Some(removed_diagnostic) = self.history.pop_front() { @@ -56,6 +68,7 @@ impl Diagnostic { self.history.clear(); self.sum = value; } + self.history .push_back(DiagnosticMeasurement { time, value }); } @@ -82,6 +95,8 @@ impl Diagnostic { history: VecDeque::with_capacity(max_history_length), max_history_length, sum: 0.0, + ema: 0.0, + ema_smoothing_factor: 2.0 / 21.0, is_enabled: true, } } @@ -93,6 +108,22 @@ impl Diagnostic { self } + /// The smoothing factor used for the exponential smoothing used for + /// [`smoothed`](Self::smoothed). + /// + /// If measurements come in less fequently than `smoothing_factor` seconds + /// apart, no smoothing will be applied. As measurements come in more + /// frequently, the smoothing takes a greater effect such that it takes + /// approximately `smoothing_factor` seconds for 83% of an instantaneous + /// change in measurement to e reflected in the smoothed value. + /// + /// A smoothing factor of 0.0 will effectively disable smoothing. + #[must_use] + pub fn with_smoothing_factor(mut self, smoothing_factor: f64) -> Self { + self.ema_smoothing_factor = smoothing_factor; + self + } + /// Get the latest measurement from this diagnostic. #[inline] pub fn measurement(&self) -> Option<&DiagnosticMeasurement> { @@ -104,7 +135,7 @@ impl Diagnostic { self.measurement().map(|measurement| measurement.value) } - /// Return the mean (average) of this diagnostic's values. + /// Return the simple moving average of this diagnostic's recent values. /// N.B. this a cheap operation as the sum is cached. pub fn average(&self) -> Option { if !self.history.is_empty() { @@ -114,6 +145,19 @@ impl Diagnostic { } } + /// Return the exponential moving average of this diagnostic. + /// + /// This is by default tuned to behave reasonably well for a typical + /// measurement that changes every frame such as frametime. This can be + /// adjusted using [`with_smoothing_factor`](Self::with_smoothing_factor). + pub fn smoothed(&self) -> Option { + if !self.history.is_empty() { + Some(self.ema) + } else { + None + } + } + /// Return the number of elements for this diagnostic. pub fn history_len(&self) -> usize { self.history.len() @@ -154,7 +198,7 @@ impl Diagnostic { } /// A collection of [Diagnostic]s -#[derive(Debug, Default)] +#[derive(Debug, Default, Resource)] pub struct Diagnostics { // This uses a [`StableHashMap`] to ensure that the iteration order is deterministic between // runs when all diagnostics are inserted in the same order. diff --git a/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs index bc07eaaad6887e..ef31006cd2b6b7 100644 --- a/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs @@ -1,5 +1,6 @@ use crate::{Diagnostic, DiagnosticId, Diagnostics}; use bevy_app::prelude::*; +use bevy_core::FrameCount; use bevy_ecs::system::{Res, ResMut}; use bevy_time::Time; @@ -7,14 +8,9 @@ use bevy_time::Time; #[derive(Default)] pub struct FrameTimeDiagnosticsPlugin; -pub struct FrameTimeDiagnosticsState { - frame_count: u64, -} - impl Plugin for FrameTimeDiagnosticsPlugin { fn build(&self, app: &mut bevy_app::App) { app.add_startup_system(Self::setup_system) - .insert_resource(FrameTimeDiagnosticsState { frame_count: 0 }) .add_system(Self::diagnostic_system); } } @@ -27,33 +23,26 @@ impl FrameTimeDiagnosticsPlugin { DiagnosticId::from_u128(73441630925388532774622109383099159699); pub fn setup_system(mut diagnostics: ResMut) { - diagnostics.add(Diagnostic::new(Self::FRAME_TIME, "frame_time", 20).with_suffix("s")); + diagnostics.add(Diagnostic::new(Self::FRAME_TIME, "frame_time", 20).with_suffix("ms")); diagnostics.add(Diagnostic::new(Self::FPS, "fps", 20)); - diagnostics.add(Diagnostic::new(Self::FRAME_COUNT, "frame_count", 1)); + diagnostics + .add(Diagnostic::new(Self::FRAME_COUNT, "frame_count", 1).with_smoothing_factor(0.0)); } pub fn diagnostic_system( mut diagnostics: ResMut, time: Res