# Objective
* Adopted #12025 to fix merge conflicts
* In some cases we used manual impls for certain types, though they are
(at least, now) unnecessary.
## Solution
* Use macros and reflecting-by-value to avoid this clutter.
* Though there were linker issues with Reflect and the CowArc in
AssetPath (see https://github.com/bevyengine/bevy/issues/9747), I
checked these are resolved by using #[reflect_value].
---------
Co-authored-by: soqb <cb.setho@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
Fixes#12600
## Solution
Removed Into<AssetId<T>> for Handle<T> as proposed in Issue
conversation, fixed dependent code
## Migration guide
If you use passing Handle by value as AssetId, you should pass reference
or call .id() method on it
Before (0.13):
`assets.insert(handle, value);`
After (0.14):
`assets.insert(&handle, value);`
or
`assets.insert(handle.id(), value);`
# Objective
- It can be useful to have access to the path of the current asset being
processed, for example if you want to need a second file that is
relative to the current file being processed.
## Solution
- I added a `path()` function to the `ProcessContext`
# Objective
Lets say I have the following `.meta` file:
```RON
(
meta_format_version: "1.0",
asset: Ignore,
)
```
When a file is inside the `assets` directory and processing is enabled,
the processor will copy the file into `imported_assets` although it
should be ignored and therefore not copied.
## Solution
- I added a simple check that does not copy the assets if the
AssetAction is `Ignore`.
## Migration Guide
- The public `ProcessResult` enum now has a `ProcessResult::Ignore`
variant that must be handled.
# Objective
Fix Pr CI failing over dead code in tests and main branch CI failing
over a missing semicolon. Fixes#12620.
## Solution
Add dead_code annotations and a semicolon.
# Objective
Simplify implementing some asset traits without Box::pin(async move{})
shenanigans.
Fixes (in part) https://github.com/bevyengine/bevy/issues/11308
## Solution
Use async-fn in traits when possible in all traits. Traits with return
position impl trait are not object safe however, and as AssetReader and
AssetWriter are both used with dynamic dispatch, you need a Boxed
version of these futures anyway.
In the future, Rust is [adding
](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html)proc
macros to generate these traits automatically, and at some point in the
future dyn traits should 'just work'. Until then.... this seemed liked
the right approach given more ErasedXXX already exist, but, no clue if
there's plans here! Especially since these are public now, it's a bit of
an unfortunate API, and means this is a breaking change.
In theory this saves some performance when these traits are used with
static dispatch, but, seems like most code paths go through dynamic
dispatch, which boxes anyway.
I also suspect a bunch of the lifetime annotations on these function
could be simplified now as the BoxedFuture was often the only thing
returned which needed a lifetime annotation, but I'm not touching that
for now as traits + lifetimes can be so tricky.
This is a revival of
[pull/11362](https://github.com/bevyengine/bevy/pull/11362) after a
spectacular merge f*ckup, with updates to the latest Bevy. Just to recap
some discussion:
- Overall this seems like a win for code quality, especially when
implementing these traits, but a loss for having to deal with ErasedXXX
variants.
- `ConditionalSend` was the preferred name for the trait that might be
Send, to deal with wasm platforms.
- When reviewing be sure to disable whitespace difference, as that's 95%
of the PR.
## Changelog
- AssetReader, AssetWriter, AssetLoader, AssetSaver and Process now use
async-fn in traits rather than boxed futures.
## Migration Guide
- Custom implementations of AssetReader, AssetWriter, AssetLoader,
AssetSaver and Process should switch to async fn rather than returning a
bevy_utils::BoxedFuture.
- Simultaniously, to use dynamic dispatch on these traits you should
instead use dyn ErasedXXX.
# Objective
fix#12344
## Solution
use existing machinery in track_assets to determine if the asset is
unused before firing Asset::Unused event
~~most extract functions use `AssetEvent::Removed` to schedule deletion
of render world resources. `RenderAssetPlugin` was using
`AssetEvent::Unused` instead.
`Unused` fires when the last strong handle is dropped, even if a new one
is created. `Removed` only fires when a new one is not created.
as far as i can see, `Unused` is the same as `Removed` except for this
"feature", and that it also fires early if all handles for a loading
asset are dropped (`Removed` fires after the loading completes). note
that in that case, processing based on `Loaded` won't have been done
anyway.
i think we should get rid of `Unused` completely, it is not currently
used anywhere (except here, previously) and i think using it is probably
always a mistake.
i also am not sure why we keep loading assets that have been dropped
while loading, we should probably drop the loader task as well and
remove immediately.~~
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/12380
## Solution
- Before #11986 AssetEvents were scheduled after PostUpdate. That pr
moved these into First. This PR moves them into Last which is closer to
how they were scheduled before.
# Objective
Fix missing `TextBundle` (and many others) which are present in the main
crate as default features but optional in the sub-crate. See:
- https://docs.rs/bevy/0.13.0/bevy/ui/node_bundles/index.html
- https://docs.rs/bevy_ui/0.13.0/bevy_ui/node_bundles/index.html
~~There are probably other instances in other crates that I could track
down, but maybe "all-features = true" should be used by default in all
sub-crates? Not sure.~~ (There were many.) I only noticed this because
rust-analyzer's "open docs" features takes me to the sub-crate, not the
main one.
## Solution
Add "all-features = true" to docs.rs metadata for crates that use
features.
## Changelog
### Changed
- Unified features documented on docs.rs between main crate and
sub-crates
This is an implementation of RFC #51:
https://github.com/bevyengine/rfcs/blob/main/rfcs/51-animation-composition.md
Note that the implementation strategy is different from the one outlined
in that RFC, because two-phase animation has now landed.
# Objective
Bevy needs animation blending. The RFC for this is [RFC 51].
## Solution
This is an implementation of the RFC. Note that the implementation
strategy is different from the one outlined there, because two-phase
animation has now landed.
This is just a draft to get the conversation started. Currently we're
missing a few things:
- [x] A fully-fleshed-out mechanism for transitions
- [x] A serialization format for `AnimationGraph`s
- [x] Examples are broken, other than `animated_fox`
- [x] Documentation
---
## Changelog
### Added
* The `AnimationPlayer` has been reworked to support blending multiple
animations together through an `AnimationGraph`, and as such will no
longer function unless a `Handle<AnimationGraph>` has been added to the
entity containing the player. See [RFC 51] for more details.
* Transition functionality has moved from the `AnimationPlayer` to a new
component, `AnimationTransitions`, which works in tandem with the
`AnimationGraph`.
## Migration Guide
* `AnimationPlayer`s can no longer play animations by themselves and
need to be paired with a `Handle<AnimationGraph>`. Code that was using
`AnimationPlayer` to play animations will need to create an
`AnimationGraph` asset first, add a node for the clip (or clips) you
want to play, and then supply the index of that node to the
`AnimationPlayer`'s `play` method.
* The `AnimationPlayer::play_with_transition()` method has been removed
and replaced with the `AnimationTransitions` component. If you were
previously using `AnimationPlayer::play_with_transition()`, add all
animations that you were playing to the `AnimationGraph`, and create an
`AnimationTransitions` component to manage the blending between them.
[RFC 51]:
https://github.com/bevyengine/rfcs/blob/main/rfcs/51-animation-composition.md
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
Make bevy_utils less of a compilation bottleneck. Tackle #11478.
## Solution
* Move all of the directly reexported dependencies and move them to
where they're actually used.
* Remove the UUID utilities that have gone unused since `TypePath` took
over for `TypeUuid`.
* There was also a extraneous bytemuck dependency on `bevy_core` that
has not been used for a long time (since `encase` became the primary way
to prepare GPU buffers).
* Remove the `all_tuples` macro reexport from bevy_ecs since it's
accessible from `bevy_utils`.
---
## Changelog
Removed: Many of the reexports from bevy_utils (petgraph, uuid, nonmax,
smallvec, and thiserror).
Removed: bevy_core's reexports of bytemuck.
## Migration Guide
bevy_utils' reexports of petgraph, uuid, nonmax, smallvec, and thiserror
have been removed.
bevy_core' reexports of bytemuck's types has been removed.
Add them as dependencies in your own crate instead.
# Objective
Fix#12304. Remove unnecessary type registrations thanks to #4154.
## Solution
Conservatively remove type registrations. Keeping the top level
components, resources, and events, but dropping everything else that is
a type of a member of those types.
# Objective
`bevy_utils::Entry` is only useful when using
`BuildHasherDefault<AHasher>`. It would be great if we didn't have to
write out `bevy_utils::hashbrown::hash_map::Entry` whenever we want to
use a different `BuildHasher`, such as when working with
`bevy_utils::TypeIdMap`.
## Solution
Give `bevy_utils::Entry` a new optional type parameter for defining a
custom `BuildHasher`, such as `NoOpHash`. This parameter defaults to
`BuildHasherDefault<AHasher>`— the `BuildHasher` used by
`bevy_utils::HashMap`.
---
## Changelog
- Added an optional third type parameter to `bevy_utils::Entry` to
specify a custom `BuildHasher`
# Objective
Fixes#11298. Make the use of bevy_log vs bevy_utils::tracing more
consistent.
## Solution
Replace all uses of bevy_log's logging macros with the reexport from
bevy_utils. Remove bevy_log as a dependency where it's no longer needed
anymore.
Ideally we should just be using tracing directly, but given that all of
these crates are already using bevy_utils, this likely isn't that great
of a loss right now.
# Objective
`FromWorld` is often used to group loading and creation of assets for
resources.
With this setup, users often end up repetitively calling
`.resource::<AssetServer>` and `.resource_mut::<Assets<T>>`, and may
have difficulties handling lifetimes of the returned references.
## Solution
Add extension methods to `World` to add and load assets, through a new
extension trait defined in `bevy_asset`.
### Other considerations
* This might be a bit too "magic", as it makes implicit the resource
access.
* We could also implement `DirectAssetAccessExt` on `App`, but it didn't
feel necessary, as `FromWorld` is the principal use-case here.
---
## Changelog
* Add the `DirectAssetAccessExt` trait, which adds the `add_asset`,
`load_asset` and `load_asset_with_settings` method to the `World` type.
# Objective
The `AssetIndex` cannot be carried across boundaries that do not allow
explicit rust types.
For context, I ran into this issue while trying to implent an
improvement for bevy_egui which leverages the not-so-new custom loader
API. Passing through a handle directly isn't possible, but instead it
requires stringified URI s. I had to work around the lack of this API s
existance using reflection, which is rather dirty.
## Solution
- Add `to_bits` and `from_bits` functions to `AssetIndex` to allow
moving this type through such boundaries.
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
Memory usage optimisation
## Solution
`HashMap` and `HashSet`'s keys are immutable. So using mutable types
like `String`, `Vec<T>`, or `PathBuf` as a key is a waste of memory:
they have an extra `usize` for their capacity and may have spare
capacity.
This PR replaces these types by their immutable equivalents `Box<str>`,
`Box<[T]>`, and `Box<Path>`.
For more context, I recommend watching the [Use Arc Instead of
Vec](https://www.youtube.com/watch?v=A4cKi7PTJSs) video.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
Fix#11845.
## Solution
Remove the `UpdateAssets` and `AssetEvents` schedules. Moved the
`UpdateAssets` systems to `PreUpdate`, and `AssetEvents` systems into
`First`. The former is meant to run before any of the event flushes.
## Future Work
It'd be ideal if we could manually flush the events for assets to avoid
needing two, sort of redundant, systems. This should at least let them
potentially run in parallel with all of the systems in the schedules
they were moved to.
---
## Changelog
Removed: `UpdateAssets` schedule from the main schedule. All systems
have been moved to `PreUpdate`.
Removed: `AssetEvents` schedule from the main schedule. All systems have
been move to `First` with the same system sets.
## Migration Guide
TODO
# Objective
- I hit an issue using the `file_watcher` feature to hot reload assets
for my game. The change in this PR allows me to now hot reload assets.
- The issue stemmed from my project being a multi crate workspace
project structured like so:
```
└── my_game
├── my_game_core
│ ├── src
│ └── assets
├── my_game_editor
│ └── src/main.rs
└── my_game
└── src/main.rs
```
- `my_game_core` is a crate that holds all my game logic and assets
- `my_game` is the crate that creates the binary for my game (depends on
the game logic and assets in `my_game_core`)
- `my_game_editor` is an editor tool for my game (it also depends on the
game logic and assets in `my_game_core`)
Whilst running `my_game` and `my_game_editor` from cargo during
development I would use `AssetPlugin` like so:
```rust
default_plugins.set(AssetPlugin {
watch_for_changes_override: Some(true),
file_path: "../my_game_core/assets".to_string(),
..Default::default()
})
```
This works fine; bevy picks up the assets. However on saving an asset I
would get the following panic from `file_watcher`. It wouldn't kill the
app, but I wouldn't see the asset hot reload:
```
thread 'notify-rs debouncer loop' panicked at /Users/ian/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_asset-0.12.1/src/io/file/file_watcher.rs:48:58:
called `Result::unwrap()` on an `Err` value: StripPrefixError(())
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
## Solution
- The solution is to collapse dot segments in the root asset path
`FileWatcher` is using
- There was already bevy code to do this in `AssetPath`, so I extracted
that code so it could be reused in `FileWatcher`
# Objective
- Sometimes, it is useful to get a `Handle<T>` from an `AssetId<T>`. For
example, when iterating `Assets` to find a specific asset. So much so
that it's possible to do so with `AssetServer::get_id_handle`
- However, `AssetServer::get_id_handle` doesn't work with assets
directly added to `Assets` using `Assets::add`.
- Fixes#12087
## Solution
- Add `Assets::get_strong_handle` to convert an `AssetId` into an
`Handle`
- Document `AssetServer::get_id_handle` to explain its limitation and
point to `get_strong_handle`.
- Add a test for `get_strong_handle`
- Add a `duplicate_handles` field to `Assets` to avoid dropping assets
with a live handle generated by `get_strong_handle` (more reference
counting yay…)
- Fix typos in `Assets` docs
---
## Changelog
- Add `Assets::get_strong_handle` to convert an `AssetId` into an
`Handle`
# Objective
When dealing with custom asset sources it can be a bit tricky to get
asset roots combined with relative paths correct.
It's even harder when it isn't mentioned which path was problematic.
## Solution
Mention which path failed for the file watcher.
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
# Objective
- The file asset source currently creates the `imported_assets/Default`
directory with relative path, which leads to wrongly created directories
when the executable is run with a working directory different from the
project root.
## Solution
- Use the full path instead.
# Objective
The derive macro wasn't doc-commented, so it showed up in the generated
doc as follow:
```rust
#[derive(Asset, TypePath)]
let shader = asset_server.load::<Shader>("embedded://bevy_rock/render/rock.wgsl");
```
Which is very confusing
## Solution
Comment the `derive` attribute as well
# Objective
Right now, if you call `embedded_asset` with 2 arguments as a qualified
path it doesn't work (`bevy::asset::embedded_asset!(app, "foo.wgsl")` ->
"cannot find macro `embedded_asset` in this scope")
## Solution
Use `$crate::` in expansion for 2-arg case.
# Objective
When registering and preregistering asset loaders, there would be a
`warn!` if multiple asset loaders use a given extension, and an `info!`
if multiple asset loaders load the same asset type. Since both of these
situations are individually fine, it was decided that these messages
should be removed.
## Solution
Replace both of these messages with a new `warn!` that notes that if
multiple asset loaders share the same asset type _and_ share extensions,
that the loader must be specified in the `.meta` file for those assets
in order to solve the ambiguity. This is a more useful message, since it
notes when a user must take special action / consideration.
# Objective
- Fixes#11638
- See
[here](https://github.com/bevyengine/bevy/issues/11638#issuecomment-1920508465)
for details on the cause of this issue.
## Solution
- Modified `AssetLoaders` to capture possibility of multiple
`AssetLoader` registrations operating on the same `Asset` type, but
different extensions.
- Added an algorithm which will attempt to resolve via `AssetLoader`
name, then `Asset` type, then by extension. If at any point multiple
loaders fit a particular criteria, the next criteria is used as a tie
breaker.
# Objective
Scheduling low cost systems has significant overhead due to task pool
contention and the extra machinery to schedule and run them. Following
the example of #7728, `asset_events` is good example of this kind of
system, where there is no work to be done when there are no queued asset
events.
## Solution
Put a run condition on it that checks if there are any queued events.
## Performance
Tested against `many_foxes`, we can see a slight improvement in the
total time spent in `UpdateAssets`. Also noted much less volatility due
to not being at the whim of the OS thread scheduler.
![image](https://github.com/bevyengine/bevy/assets/3137680/e0b282bf-27d0-4fe4-81b9-ecd72ab258e5)
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fix https://github.com/bevyengine/bevy/issues/11657
## Solution
Add a `ReflectKind` enum, add `Reflect::reflect_kind` which returns a
`ReflectKind`, and add `kind` method implementions to `ReflectRef`,
`ReflectMut`, and `ReflectOwned`, which returns a `ReflectKind`.
I also changed `AccessError` to use this new struct instead of it's own
`TypeKind` struct.
---
## Changelog
- Added `ReflectKind`, an enumeration over the kinds of a reflected type
without its data.
- Added `Reflect::reflect_kind` (with default implementation)
- Added implementation for the `kind` method on `ReflectRef`,
`ReflectMut`, and `ReflectOwned` which gives their kind without any
information, as a `ReflectKind`
Use `TypeIdMap<T>` instead of `HashMap<TypeId, T>`
- ~~`TypeIdMap` was in `bevy_ecs`. I've kept it there because of
#11478~~
- ~~I haven't swapped `bevy_reflect` over because it doesn't depend on
`bevy_ecs`, but I'd also be happy with moving `TypeIdMap` to
`bevy_utils` and then adding a dependency to that~~
- ~~this is a slight change in the public API of
`DrawFunctionsInternal`, does this need to go in the changelog?~~
## Changelog
- moved `TypeIdMap` to `bevy_utils`
- changed `DrawFunctionsInternal::indices` to `TypeIdMap`
## Migration Guide
- `TypeIdMap` now lives in `bevy_utils`
- `DrawFunctionsInternal::indices` now uses a `TypeIdMap`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Currently the `missing_docs` lint is allowed-by-default and enabled at
crate level when their documentations is complete (see #3492).
This PR proposes to inverse this logic by making `missing_docs`
warn-by-default and mark crates with imcomplete docs allowed.
## Solution
Makes `missing_docs` warn at workspace level and allowed at crate level
when the docs is imcomplete.
# Objective
- `AssetTransformer` provides an input asset, and output an asset, but
provides no access to the `LabeledAsset`'s created by the `AssetLoader`.
Labeled sub assets are an extremely important piece of many assets, Gltf
in particular, and without them the amount of transformation on an asset
is limited. In order for `AssetTransformer`'s to be useful, they need to
have access to these sub assets.
- LabeledAsset's loaded by `AssetLoader`s are provided to `AssetSaver`s
in the `LoadAndSave` process, but the `LoadTransformAndSave` process
drops these values in the transform stage, and so `AssetSaver` is given
none.
- Fixes#11606
Ideally the AssetTransformer should not ignore labeled sub assets, and
they should be kept at least for the AssetSaver
## Solution
- I created a new struct similar to `SavedAsset` named
`TransformedAsset` which holds the input asset, and the HashMap of
`LabeledAsset`s. The transform function now takes as input a
`TransformedAsset`, and returns a `TransformedAsset::<AssetOutput>`.
This gives the transform function access to the labeled sub assets
created by the `AssetLoader`.
- I also created `TransformedSubAsset` which holds mutable references to
a sub asset and that sub assets HashMap of `LabeledAsset`s. This allows
you to travers the Tree of `LabeledAsset`s by reference relatively
easily.
- The `LoadTransformAndSave` processor was then reworked to use the new
structs, stopping the `LabeledAsset`s from being dropped.
---
## Changelog
- Created TransformedAsset struct and TransformedSubAsset struct.
- Changed `get_untyped_handle` to return a `UntypedHandle` directly
rather than a reference and added `get_handle` as a typed variant in
SavedAsset and TransformedAsset
- Added `SavedAsset::from_transformed` as a constructor from a
`TransformedAsset`
- Switched LoadTransformAndSave process code to work with new
`TransformedAsset` type
- Added a `ProcessError` for `AssetTransformer` in process.rs
- Switched `AssetTransformer::transform` to use `TransformedAsset` as
input and output.
- Switched `AssetTransformer` to use a `BoxedFuture` like `AssetLoader`
and `AssetSaver` to allow for async transformation code.
- Updated AssetTransformer example to use new structure.
# Objective
- Addresses **Support processing and loading files without extensions**
from #9714
- Addresses **More runtime loading configuration** from #9714
- Fixes#367
- Fixes#10703
## Solution
`AssetServer::load::<A>` and `AssetServer::load_with_settings::<A>` can
now use the `Asset` type parameter `A` to select a registered
`AssetLoader` without inspecting the provided `AssetPath`. This change
cascades onto `LoadContext::load` and `LoadContext::load_with_settings`.
This allows the loading of assets which have incorrect or ambiguous file
extensions.
```rust
// Allow the type to be inferred by context
let handle = asset_server.load("data/asset_no_extension");
// Hint the type through the handle
let handle: Handle<CustomAsset> = asset_server.load("data/asset_no_extension");
// Explicit through turbofish
let handle = asset_server.load::<CustomAsset>("data/asset_no_extension");
```
Since a single `AssetPath` no longer maps 1:1 with an `Asset`, I've also
modified how assets are loaded to permit multiple asset types to be
loaded from a single path. This allows for two different `AssetLoaders`
(which return different types of assets) to both load a single path (if
requested).
```rust
// Uses GltfLoader
let model = asset_server.load::<Gltf>("cube.gltf");
// Hypothetical Blob loader for data transmission (for example)
let blob = asset_server.load::<Blob>("cube.gltf");
```
As these changes are reflected in the `LoadContext` as well as the
`AssetServer`, custom `AssetLoaders` can also take advantage of this
behaviour to create more complex assets.
---
## Change Log
- Updated `custom_asset` example to demonstrate extension-less assets.
- Added `AssetServer::get_handles_untyped` and Added
`AssetServer::get_path_ids`
## Notes
As a part of that refactor, I chose to store `AssetLoader`s (within
`AssetLoaders`) using a `HashMap<TypeId, ...>` instead of a `Vec<...>`.
My reasoning for this was I needed to add a relationship between `Asset`
`TypeId`s and the `AssetLoader`, so instead of having a `Vec` and a
`HashMap`, I combined the two, removing the `usize` index from the
adjacent maps.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- SavedAsset's iter_labels returns ```&str```, however accessing
LabeledAssets requires ```CowArc<'static, str>```
- Although SavedAsset holds UntypedHandles in its hashmap of
LabeledAssets, they are inaccessible as LabeledAssets are casted to
SavedAsset or ErasedLoadedAsset, which don't contain their
UntypedHandles
- Adresses #11609
## Solution
- Used Trait bounds to allow for either ```CowArc<'static, str>``` or
```&str``` to be used as a label in get_labeled and get_erased_labeled.
- Added method get_untyped_handle to get UntypedHandle from the
LabeledAsset.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Revert the changes to type parameter bounds introduced in #9046,
improves the `#[reflect(where)]` attribute (also from #9046), and adds
the ability to opt out of field bounds.
This is based on suggestions by @soqb and discussion on
[Discord](https://discord.com/channels/691052431525675048/1002362493634629796/1201227833826103427).
## Solution
Reverts the changes to type parameter bounds when deriving `Reflect`,
introduced in #9046. This was originally done as a means of fixing a
recursion issue (#8965). However, as @soqb pointed out, we could achieve
the same result by simply making an opt-out attribute instead of messing
with the type parameter bounds.
This PR has four main changes:
1. Reverts the type parameter bounds from #9046
2. Includes `TypePath` as a default bound for active fields
3. Changes `#reflect(where)]` to be strictly additive
4. Adds `#reflect(no_field_bounds)]` to opt out of field bounds
Change 1 means that, like before, type parameters only receive at most
the `TypePath` bound (if `#[reflect(type_path = false)]` is not present)
and active fields receive the `Reflect` or `FromReflect` bound. And with
Change 2, they will also receive `TypePath` (since it's indirectly
required by `Typed` to construct `NamedField` and `UnnamedField`
instances).
Change 3 was made to make room for Change 4. By splitting out the
responsibility of `#reflect(where)]`, we can use it with or without
`#reflect(no_field_bounds)]` for various use cases.
For example, if we hadn't done this, the following would have failed:
```rust
// Since we're not using `#reflect(no_field_bounds)]`,
// `T::Assoc` is automatically given the required bounds
// of `FromReflect + TypePath`
#[derive(Reflect)]
#[reflect(where T::Assoc: OtherTrait)]
struct Foo<T: MyTrait> {
value: T::Assoc,
}
```
This provides more flexibility to the user while still letting them add
or remove most trait bounds.
And to solve the original recursion issue, we can do:
```rust
#[derive(Reflect)]
#[reflect(no_field_bounds)] // <-- Added
struct Foo {
foo: Vec<Foo>
}
```
#### Bounds
All in all, we now have four sets of trait bounds:
- `Self` gets the bounds `Any + Send + Sync`
- Type parameters get the bound `TypePath`. This can be opted out of
with `#[reflect(type_path = false)]`
- Active fields get the bounds `TypePath` and `FromReflect`/`Reflect`
bounds. This can be opted out of with `#reflect(no_field_bounds)]`
- Custom bounds can be added with `#[reflect(where)]`
---
## Changelog
- Revert some changes #9046
- `#reflect(where)]` is now strictly additive
- Added `#reflect(no_field_bounds)]` attribute to opt out of automatic
field trait bounds when deriving `Reflect`
- Made the `TypePath` requirement on fields when deriving `Reflect` more
explicit
## Migration Guide
> [!important]
> This PR shouldn't be a breaking change relative to the current version
of Bevy (v0.12). And since it removes the breaking parts of #9046, that
PR also won't need a migration guide.
# Objective
- Closes#11490.
- Allow retrieving the current asset watch behavior from the
`AssetServer`.
## Solution
- Add the corresponding getter. (also fixes some trailing whitespace).
A corresponding helper could also be added on the `AssetPlugin` struct
(returning `self.watch_for_changes_override.unwrap_or(cfg!(feature =
"watch"))`), but it seems it isn't a current practice to have actual
methods on the plugin structs appart from the `Plugin` impl.
---
## Changelog
### Added
Added `watching_for_changes` getter on `AssetServer`.
---------
Co-authored-by: Mateusz Wachowiak <mateusz_wachowiak@outlook.com>
# Objective
Fixes#8965.
#### Background
For convenience and to ensure everything is setup properly, we
automatically add certain bounds to the derived types. The current
implementation does this by taking the types from all active fields and
adding them to the where-clause of the generated impls. I believe this
method was chosen because it won't add bounds to types that are
otherwise ignored.
```rust
#[derive(Reflect)]
struct Foo<T, U: SomeTrait, V> {
t: T,
u: U::Assoc,
#[reflect(ignore)]
v: [V; 2]
}
// Generates something like:
impl<T, U: SomeTrait, V> for Foo<T, U, V>
where
// Active:
T: Reflect,
U::Assoc: Reflect,
// Ignored:
[V; 2]: Send + Sync + Any
{
// ...
}
```
The self-referential type fails because it ends up using _itself_ as a
type bound due to being one of its own active fields.
```rust
#[derive(Reflect)]
struct Foo {
foo: Vec<Foo>
}
// Foo where Vec<Foo>: Reflect -> Vec<T> where T: Reflect -> Foo where Vec<Foo>: Reflect -> ...
```
## Solution
We can't simply parse all field types for the name of our type. That
would be both complex and prone to errors and false-positives. And even
if it wasn't, what would we replace the bound with?
Instead, I opted to go for a solution that only adds the bounds to what
really needs it: the type parameters. While the bounds on concrete types
make errors a bit cleaner, they aren't strictly necessary. This means we
can change our generated where-clause to only add bounds to generic type
parameters.
Doing this, though, returns us back to the problem of over-bounding
parameters that don't need to be bounded. To solve this, I added a new
container attribute (based on
[this](https://github.com/dtolnay/syn/issues/422#issuecomment-406882925)
comment and @nicopap's
[comment](https://github.com/bevyengine/bevy/pull/9046#issuecomment-1623593780))
that allows us to pass in a custom where clause to modify what bounds
are added to these type parameters.
This allows us to do stuff like:
```rust
trait Trait {
type Assoc;
}
// We don't need `T` to be reflectable since we only care about `T::Assoc`.
#[derive(Reflect)]
#[reflect(where T::Assoc: FromReflect)]
struct Foo<T: Trait>(T::Assoc);
#[derive(TypePath)]
struct Bar;
impl Trait for Bar {
type Assoc = usize;
}
#[derive(Reflect)]
struct Baz {
a: Foo<Bar>,
}
```
> **Note**
> I also
[tried](dc139ea34c)
allowing `#[reflect(ignore)]` to be used on the type parameters
themselves, but that proved problematic since the derive macro does not
consume the attribute. This is why I went with the container attribute
approach.
### Alternatives
One alternative could possibly be to just not add reflection bounds
automatically (i.e. only add required bounds like `Send`, `Sync`, `Any`,
and `TypePath`).
The downside here is we add more friction to using reflection, which
already comes with its own set of considerations. This is a potentially
viable option, but we really need to consider whether or not the
ergonomics hit is worth it.
If we did decide to go the more manual route, we should at least
consider something like #5772 to make it easier for users to add the
right bounds (although, this could still become tricky with
`FromReflect` also being automatically derived).
### Open Questions
1. Should we go with this approach or the manual alternative?
2. ~~Should we add a `skip_params` attribute to avoid the `T: 'static`
trick?~~ ~~Decided to go with `custom_where()` as it's the simplest~~
Scratch that, went with a normal where clause
3. ~~`custom_where` bikeshedding?~~ No longer needed since we are using
a normal where clause
### TODO
- [x] Add compile-fail tests
---
## Changelog
- Fixed issue preventing recursive types from deriving `Reflect`
- Changed how where-clause bounds are generated by the `Reflect` derive
macro
- They are now only applied to the type parameters, not to all active
fields
- Added `#[reflect(where T: Trait, U::Assoc: Trait, ...)]` container
attribute
## Migration Guide
When deriving `Reflect`, generic type params that do not need the
automatic reflection bounds (such as `Reflect`) applied to them will
need to opt-out using a custom where clause like: `#[reflect(where T:
Trait, U::Assoc: Trait, ...)]`.
The attribute can define custom bounds only used by the reflection
impls. To simply opt-out all the type params, we can pass in an empty
where clause: `#[reflect(where)]`.
```rust
// BEFORE:
#[derive(Reflect)]
struct Foo<T>(#[reflect(ignore)] T);
// AFTER:
#[derive(Reflect)]
#[reflect(where)]
struct Foo<T>(#[reflect(ignore)] T);
```
---------
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
# Objective
Fixes#11533
When `AssetPath`s are created from a string type, they are parsed into
an `AssetSource`, a `Path`, and a `Label`.
The current method of parsing has some unnecessary quirks:
- The presence of a `:` character is assumed to be the start of an asset
source indicator.
- This is not necessarily true. There are valid uses of a `:` character
in an asset path, for example an http source's port such as
`localhost:80`.
- If there are multiple instances of `://`, the last one is assumed to
be the asset source deliminator.
- This has some unexpected behavior. Even in a fully formed path, such
as `http://localhost:80`, the `:` between `localhost` and `80` is
assumed to be the start of an asset source, causing an error since it
does not form the full sequence `://`.
## Solution
Changes the `AssetPath`'s `parse_internal` method to be more permissive.
- Only the exact sequence `://` is taken to be the asset source
deliminator, and only the first one if there are multiple.
- As a consequence, it is no longer possible to detect a malformed asset
source deliminator, and so the corresponding error was removed.
# Objective
One of a few Bevy Asset improvements I would like to make: #11216.
Currently asset processing and asset saving are handled by the same
trait, `AssetSaver`. This makes it difficult to reuse saving
implementations and impossible to have a single "universal" saver for a
given asset type.
## Solution
This PR splits off the processing portion of `AssetSaver` into
`AssetTransformer`, which is responsible for transforming assets. This
change involves adding the `LoadTransformAndSave` processor, which
utilizes the new API. The `LoadAndSave` still exists since it remains
useful in situations where no "transformation" of the asset is done,
such as when compressing assets.
## Notes:
As an aside, Bikeshedding is welcome on the names. I'm not entirely
convinced by `AssetTransformer`, which was chosen mostly because
`AssetProcessor` is taken. Additionally, `LoadTransformSave` may be
sufficient instead of `LoadTransformAndSave`.
---
## Changelog
### Added
- `AssetTransformer` which is responsible for transforming Assets.
- `LoadTransformAndSave`, a `Process` implementation.
### Changed
- Changed `AssetSaver`'s responsibilities from processing and saving to
just saving.
- Updated `asset_processing` example to use new API.
- Old asset .meta files regenerated with new processor.
# Objective
- Fix documentation for `AssetReader::is_directory` (it is currently
exactly the same as docs for `read_directory`)
---------
Co-authored-by: Kanabenki <lucien.menassol@gmail.com>
# Objective
TypeUuid is deprecated, remove it.
## Migration Guide
Convert any uses of `#[derive(TypeUuid)]` with `#[derive(TypePath]` for
more complex uses see the relevant
[documentation](https://docs.rs/bevy/latest/bevy/prelude/trait.TypePath.html)
for more information.
---------
Co-authored-by: ebola <dev@axiomatic>
# Objective
- Fixes a hurdle encountered when debugging a panic caused by the file
watcher loading a `.gitignore` file, which was hard to debug because
there was no file name in the report, only `asset paths must have
extensions`
## Solution
- Panic with a formatted message that includes the asset path, e.g.
`missing expected extension for asset path .gitignore`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Doonv <58695417+doonv@users.noreply.github.com>
# Objective
- `AssetPath` implements reflection, but is not registered as a type in
the plugin.
- Fixes#11481.
## Solution
- Register the `AssetPath` type when `AssetPlugin::build` is called.
---
## Changelog
- Registered `AssetPath` type for use in reflection.
# Objective
- Since #11218, example `asset_processing` fails:
```
thread 'main' panicked at crates/bevy_asset/src/io/source.rs:489:18:
Failed to create file watcher: Error { kind: PathNotFound, paths: ["examples/asset/processing/imported_assets/Default"] }
```
start from a fresh git clone or delete the folder before running to
reproduce, it is in gitignore and should not be present on a fresh run
a657478675/.gitignore (L18)
## Solution
- Auto create the `imported_assets` folder if it is configured
---------
Co-authored-by: Kyle <37520732+nvdaz@users.noreply.github.com>