# Objective
- Fixes#6370
- Closes#6581
## Solution
- Added the following lints to the workspace:
- `std_instead_of_core`
- `std_instead_of_alloc`
- `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.
## Testing
- Ran CI locally
## Migration Guide
The MSRV is now 1.81. Please update to this version or higher.
## Notes
- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
> Rust 1.81 released the #[expect(...)] attribute, which works like
#[allow(...)] but throws a warning if the lint isn't raised. This is
preferred to #[allow(...)] because it tells us when it can be removed.
- Adopts the parts of #15118 that are complete, and updates the branch
so it can be merged.
- There were a few conflicts, let me know if I misjudged any of 'em.
Alice's
[recommendation](https://github.com/bevyengine/bevy/issues/15059#issuecomment-2349263900)
seems well-taken, let's do this crate by crate now that @BD103 has done
the lion's share of this!
(Relates to, but doesn't yet completely finish #15059.)
Crates this _doesn't_ cover:
- bevy_input
- bevy_gilrs
- bevy_window
- bevy_winit
- bevy_state
- bevy_render
- bevy_picking
- bevy_core_pipeline
- bevy_sprite
- bevy_text
- bevy_pbr
- bevy_ui
- bevy_gltf
- bevy_gizmos
- bevy_dev_tools
- bevy_internal
- bevy_dylib
---------
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
Co-authored-by: Antony <antony.m.3012@gmail.com>
# Objective
Bevy's asset system is powerful and generally well-designed but very
opaque.
Beginners struggle to discover how to do simple tasks and grok the
fundamental data models, while more advanced users trip over the
assorted traits and their relation to each other.
Reverts #15054 ;)
## Solution
This PR adds module documentation to `bevy_assets`, tweaking the
associated documentation on the items as needed to provide further
details and bread crumbs.
If you have ideas for other important, hard-to-discover patterns or
functionality in this crate, please let me know.
That said, I've left out a section on asset preprocessing which *should*
eventually go here. That is substantially more uncertain, and requires
both more time to investigate and more expertise to review.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: TrialDragon <31419708+TrialDragon@users.noreply.github.com>
Co-authored-by: NotAFile <notafile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14975
## Solution
- Replace usages of `bevy_utils::CowArc` with `atomicow::CowArc`
- Remove bevy_utils::CowArc
## Testing
- `bevy_asset` test suite continues to pass.
---
## Migration Guide
`bevy_utils::CowArc` has moved to a new crate called
[atomicow](https://crates.io/crates/atomicow).
# Objective
- Allow not only inserting `Data` into `EmbeddedAssetRegistry` and `Dir`
in turn but now also removing it again.
- This way when used to embed asset data from *somewhere* but not load
it using the conventional means via `AssetServer` (which I observed
takes ownership of the `Data`) the `Data` does not need to stay in
memory of the `EmbeddedAssetRegistry` throughout the lifetime of the
application.
## Solution
- added the `remove_asset` functions in `EmbeddedAssetRegistry` and
`Dir`
## Testing
- added a module unittest
- does this require changes if build with feature `embedded_watcher`?
# Objective
When trying to test a gizmos change I ran `cargo test -p bevy_gizmos`
and the output had a lot of noise from warnings and failed doc errors.
This was because I didn't have all of the features enabled.
## Solution
I admit this might be pedantic, and am happy if the concensus is to
reject it. Although it does reduce the lines of code, testing noise, and
the amount of code compiled. I don't think it affects the complexity of
public code, and it doesn't change much to the complexity of internal
code.
I've removed un-needed `bevy_render` imports in all of the gizmos docs
examples, there's probably other unnecessary ones there too, but I
haven't looked exhaustively. It isn't needed for those docs, and isn't
available except in a subset of `cfg` combinations.
I've also made several of the `use` statements slightly more specific. I
shouldn't have changed the public interfaces, except that
`GizmoMeshConfig` requires either `bevy_sprite` or `bevy_pbr`, as it
does nothing without them.
I've also avoided adding some systems and plugins in situations where
they can't work. An example of this is where the `light` module depends
on `all(feature = "bevy_pbr", feature = "bevy_render")`, but it has
`use` statements that only require `bevy_render`.
## Testing
During development I ran:
```
cargo check -p bevy_gizmos && cargo check -p bevy_gizmos --features=bevy_pbr && cargo check -p bevy_gizmos --features=bevy_sprite && cargo check -p bevy_gizmos --features=bevy_render
```
Afterwards I ran this just to be sure:
```
cargo check && cargo check --features=bevy_pbr && cargo check --features=bevy_sprite && cargo check --features=bevy_render
```
Finally I ran:
```
cargo test -p bevy_gizmos && cargo test -p bevy_gizmos --features=bevy_pbr && test check -p bevy_gizmos --features=bevy_sprite && cargo test -p bevy_gizmos --features=bevy_render
```
## Migration Guide
There shouldn't be any reason to migrate, although if for some reason
you use `GizmoMeshConfig` and `bevy_render` but not `bevy_pbr` or
`bevy_sprite` (such that it does nothing), then you will get an error
that it no longer exists.
# Objective
Fixes#14782
## Solution
Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?
Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.
## Testing
`cargo clippy` and `cargo run -p ci` are happy.
# Objective
- Fixes#10478
## Solution
Generalised `From/Into` implementations over `&str` and `Option<&str>`
for `AssetSourceId` and `AssetPath` across all lifetimes, not just
static. To maintain access to the `'static`-only specialisation, these
types (and `CowArc`) now include an `as_static` method which will apply
the specialisation.
```rust
// Snipped from `AssetApp`
fn register_asset_source(
&mut self,
id: impl Into<AssetSourceId<'static>>,
// ^^^^^^^
// | as_static is only available for 'static lifetimes
source: AssetSourceBuilder,
) -> &mut Self {
let id = id.into().as_static();
// ^^^^^^ ^^^^^^^^^
// | | Specialized (internally storing CowArc::Static)
// | Generic Into (internally storing CowArc::Borrowed)
// ...
}
```
This post-fix specialisation is available here because the actual
specialisation performed is only a marker for if/when modification or
ownership is required, making the transform a very cheap operation. For
cleanliness, I've also added `from_static`, which wraps this behaviour
in a clean shorthand designed to replace `from` calls.
---
## Changelog
- Generalised the following implementations over a generic lifetime:
- `From<&'static str> for AssetSourceId<'static>`
- `From<Option<&'static str>> for AssetSourceId<'static>`
- `From<&'static str> for AssetPath<'static>`
- `From<&'static Path> for AssetPath<'static>`
- Added `as_static` specialisation to:
- `CowArc`
- `AssetSourceId`
- `AssetPath`
- Added `from_static` specialised constructor to:
- `AssetSourceId`
- `AssetPath`
## Migration Guide
In areas where these implementations where being used, you can now add
`from_static` in order to get the original specialised implementation
which avoids creating an `Arc` internally.
```rust
// Before
let asset_path = AssetPath::from("my/path/to/an/asset.ext");
// After
let asset_path = AssetPath::from_static("my/path/to/an/asset.ext");
```
To be clear, this is only required if you wish to maintain the
performance benefit that came with the specialisation. Existing code is
_not_ broken by this change.
# Objective
Explicitly and exactly know what of the environment variables (if any)
are being used/not-used/found-not-found by the
`bevy_asset::io::file::get_base_path()`.
- Describe the objective or issue this PR addresses:
In a sufficiently complex project, with enough crates and such it _can_
be hard to know what the Asset Server is using as, what in the bevy
parlance is its 'base path', this change seems to be the lowest effort
to discovering that.
## Solution
- Added `debug!` logging to the `FileAssetReader::new()` call.
## Testing
See output by making a project and trying something like
`RUST_LOG=bevy_asset::io::file=debug cargo run`
- Ran Bevy's tests.
- How can other people (reviewers) test your changes?: Intentionally
mess with your `env` variables (BEVY_ASSET_ROOT and CARGO_MANIFEST_DIR,
scatter assets about and attempt to (without this change) locate where
it's going wrong.
- Is there anything specific they need to know?: I encountered this
issue in a rather large workspace with many many crates with multiple
nested asset directories.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test? Linux.
---
# Objective
- `EmptyPathStream` is only used in android and wasm32
- This now makes rust nightly warn
## Solution
- flag the struct to only be present when needed
- also change how `MorphTargetNames` is used because that makes rust
happier?
# Objective
The `AssetReader` trait allows customizing the behavior of fetching
bytes for an `AssetPath`, and expects implementors to return `dyn
AsyncRead + AsyncSeek`. This gives implementors of `AssetLoader` great
flexibility to tightly integrate their asset loading behavior with the
asynchronous task system.
However, almost all implementors of `AssetLoader` don't use the async
functionality at all, and just call `AsyncReadExt::read_to_end(&mut
Vec<u8>)`. This is incredibly inefficient, as this method repeatedly
calls `poll_read` on the trait object, filling the vector 32 bytes at a
time. At my work we have assets that are hundreds of megabytes which
makes this a meaningful overhead.
## Solution
Turn the `Reader` type alias into an actual trait, with a provided
method `read_to_end`. This provided method should be more efficient than
the existing extension method, as the compiler will know the underlying
type of `Reader` when generating this function, which removes the
repeated dynamic dispatches and allows the compiler to make further
optimizations after inlining. Individual implementors are able to
override the provided implementation -- for simple asset readers that
just copy bytes from one buffer to another, this allows removing a large
amount of overhead from the provided implementation.
Now that `Reader` is an actual trait, I also improved the ergonomics for
implementing `AssetReader`. Currently, implementors are expected to box
their reader and return it as a trait object, which adds unnecessary
boilerplate to implementations. This PR changes that trait method to
return a pseudo trait alias, which allows implementors to return `impl
Reader` instead of `Box<dyn Reader>`. Now, the boilerplate for boxing
occurs in `ErasedAssetReader`.
## Testing
I made identical changes to my company's fork of bevy. Our app, which
makes heavy use of `read_to_end` for asset loading, still worked
properly after this. I am not aware if we have a more systematic way of
testing asset loading for correctness.
---
## Migration Guide
The trait method `bevy_asset::io::AssetReader::read` (and `read_meta`)
now return an opaque type instead of a boxed trait object. Implementors
of these methods should change the type signatures appropriately
```rust
impl AssetReader for MyReader {
// Before
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
let reader = // construct a reader
Box::new(reader) as Box<Reader<'a>>
}
// After
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
// create a reader
}
}
```
`bevy::asset::io::Reader` is now a trait, rather than a type alias for a
trait object. Implementors of `AssetLoader::load` will need to adjust
the method signature accordingly
```rust
impl AssetLoader for MyLoader {
async fn load<'a>(
&'a self,
// Before:
reader: &'a mut bevy::asset::io::Reader,
// After:
reader: &'a mut dyn bevy::asset::io::Reader,
_: &'a Self::Settings,
load_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
}
```
Additionally, implementors of `AssetReader` that return a type
implementing `futures_io::AsyncRead` and `AsyncSeek` might need to
explicitly implement `bevy::asset::io::Reader` for that type.
```rust
impl bevy::asset::io::Reader for MyAsyncReadAndSeek {}
```
I updated my 'main' branch, which accidentally closed the original PR
#13747. I'm reopening the this from an actual branch on my repo like I
should have done in the first place. Here's the original info from the
first PR:
* * *
# Problem
The `file_watcher` feature panics if the file_watcher's path "assets" is
not present. I stumbled upon this behavior when I was actually testing
against `embedded_watcher`. I had no "assets" directory and didn't need
one for [my project](https://github.com/shanecelis/bevy_plane_cut).
```text
$ cargo run --example simple; # Runs fine.
$ cargo run --example simple --feature embedded_watcher; # Panics
thread 'main' panicked at /Users/shane/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_asset-0.14.0-rc.2/src/io/source.rs:503:21:
Failed to create file watcher from path "assets", Error { kind: PathNotFound, paths: ["/Users/shane/Projects/bevy_plane_cut/assets"] }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
# Opinion
If a project runs without panicing, then adding the `file_watcher`
feature shouldn't cause it to panic.
# Suggested Solution
This PR suggests if the "assets" path does not exist, emit a warning
stating that the file watcher could not be created and why. All other
errors will be treated as before with a panic and a message.
```text
$ cargo run --example simple --feature embedded_watcher; # Panics
2024-06-08T08:55:11.385249Z WARN bevy_asset::io::source: Skip creating file watcher because path "assets" does not exist.
2024-06-08T08:55:11.385291Z WARN bevy_asset::io::source: AssetSourceId::Default does not have an AssetWatcher configured. Consider enabling the `file_watcher` feature.
```
The second warning is new and I'd prefer it didn't emit under this
condition, but I'll wait to see whether this is actually regarded as a
bug.
# Testing
No tests added. Compiled against my project and it demonstrated the
suggested behavior.
* * *
I changed the second warning to the following when the `file_watcher`
feature is present. When it's not present, it uses the same warning as
before.
```
024-06-09T01:22:16.880619Z WARN bevy_asset::io::source: Skip creating file watcher because path "assets" does not exist.
2024-06-09T01:22:16.880660Z WARN bevy_asset::io::source: AssetSourceId::Default does not have an AssetWatcher configured. Consider adding an "assets" directory.
```
A naked unwrap led to an opaque error that can be hit when using the
embedded filewatcher.
I've changed this an unwrap_or_else panic! with the error message
providing more details about the failed operation.
A better solution would be to print an error! and not panic...
This was tested with the asset_processing example.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#12966
## Solution
Renaming multi_threaded feature to match snake case
## Migration Guide
Bevy feature multi-threaded should be refered to multi_threaded from now
on.
# Objective
- Fixes#13024.
## Solution
- Run `cargo clippy --target wasm32-unknown-unknown` until there are no
more errors.
- I recommend reviewing one commit at a time :)
---
## Changelog
- Fixed Clippy lints for `wasm32-unknown-unknown` target.
- Updated `bevy_transform`'s `README.md`.
# Objective
This is a necessary precursor to #9122 (this was split from that PR to
reduce the amount of code to review all at once).
Moving `!Send` resource ownership to `App` will make it unambiguously
`!Send`. `SubApp` must be `Send`, so it can't wrap `App`.
## Solution
Refactor `App` and `SubApp` to not have a recursive relationship. Since
`SubApp` no longer wraps `App`, once `!Send` resources are moved out of
`World` and into `App`, `SubApp` will become unambiguously `Send`.
There could be less code duplication between `App` and `SubApp`, but
that would break `App` method chaining.
## Changelog
- `SubApp` no longer wraps `App`.
- `App` fields are no longer publicly accessible.
- `App` can no longer be converted into a `SubApp`.
- Various methods now return references to a `SubApp` instead of an
`App`.
## Migration Guide
- To construct a sub-app, use `SubApp::new()`. `App` can no longer
convert into `SubApp`.
- If you implemented a trait for `App`, you may want to implement it for
`SubApp` as well.
- If you're accessing `app.world` directly, you now have to use
`app.world()` and `app.world_mut()`.
- `App::sub_app` now returns `&SubApp`.
- `App::sub_app_mut` now returns `&mut SubApp`.
- `App::get_sub_app` now returns `Option<&SubApp>.`
- `App::get_sub_app_mut` now returns `Option<&mut SubApp>.`
# Objective
For some asset loaders, it can be useful not to read the entire asset
file and just read a specific region of a file. For this, we need a way
to seek at a specific position inside the file
## Solution
I added support for `AsyncSeek` to `Reader`. In my case, I want to only
read a part of a file, and for that I need to seek to a specific point.
## Migration Guide
Every custom reader (which previously only needed the `AsyncRead` trait
implemented) now also needs to implement the `AsyncSeek` trait to add
the seek capability.
# Objective
This PR fixes#12125
## Solution
The logic in this PR was borrowed from gloo-net and essentially probes
the global Javascript context to see if we are in a window or a worker
before calling `fetch_with_str`.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
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
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
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
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
- 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
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
- 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
- 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
- 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
- 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>
# Objective
This adds events for assets that fail to load along with minor utility
methods to make them useful. This paves the way for users writing their
own error handling and retry systems, plus Bevy including robust retry
handling: #11349.
* Addresses #11288
* Needed for #11349
# Solution
```rust
/// An event emitted when a specific [`Asset`] fails to load.
#[derive(Event, Clone, Debug)]
pub struct AssetLoadFailedEvent<A: Asset> {
pub id: AssetId<A>,
/// The original handle returned when the asset load was requested.
pub handle: Option<Handle<A>>,
/// The asset path that was attempted.
pub path: AssetPath<'static>,
/// Why the asset failed to load.
pub error: AssetLoadError,
}
```
I started implementing `AssetEvent::Failed` like suggested in #11288,
but decided it was better as its own type because:
* I think it makes sense for `AssetEvent` to only refer to assets that
actually exist.
* In order to return `AssetLoadError` in the event (which is useful
information for error handlers that might attempt a retry) we would have
to remove `Copy` from `AssetEvent`.
* There are numerous places in the render app that match against
`AssetEvent`, and I don't think it's worth introducing extra noise about
assets that don't exist.
I also introduced `UntypedAssetLoadErrorEvent`, which is very useful in
places that need to support type flexibility, like an Asset-agnostic
retry plugin.
# Changelog
* **Added:** `AssetLoadFailedEvent<A>`
* **Added**: `UntypedAssetLoadFailedEvent`
* **Added:** `AssetReaderError::Http` for status code information on
HTTP errors. Before this, status codes were only available by parsing
the error message of generic `Io` errors.
* **Added:** `asset_server.get_path_id(path)`. This method simply gets
the asset id for the path. Without this, one was left using
`get_path_handle(path)`, which has the overhead of returning a strong
handle.
* **Fixed**: Made `AssetServer` loads return the same handle for assets
that already exist in a failed state. Now, when you attempt a `load`
that's in a `LoadState::Failed` state, it'll re-use the original asset
id. The advantage of this is that any dependent assets created using the
original handle will "unbreak" if a retry succeeds.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Tried using "embedded_watcher" feature and `embedded_asset!()` from
another crate. The assets embedded fine but were not "watched." The
problem appears to be that checking for the feature was done inside the
macro, so rather than checking if "embedded_watcher" was enabled for
bevy, it would check if it was enabled for the current crate.
## Solution
I extracted the checks for the "embedded_watcher" feature into its own
function called `watched_path()`. No external changes.
### Alternative Solution
An alternative fix would be to not do any feature checking in
`embedded_asset!()` or an extracted function and always send the
full_path to `insert_asset()` where it's promptly dropped when the
feature isn't turned on. That would be simpler.
```
($app: ident, $source_path: expr, $path: expr) => {{
let mut embedded = $app
.world
.resource_mut::<$crate::io::embedded::EmbeddedAssetRegistry>();
let path = $crate::embedded_path!($source_path, $path);
//#[cfg(feature = "embedded_watcher")]
let full_path = std::path::Path::new(file!()).parent().unwrap().join($path);
//#[cfg(not(feature = "embedded_watcher"))]
//let full_path = std::path::PathBuf::new();
embedded.insert_asset(full_path, &path, include_bytes!($path));
}};
```
## Changelog
> Fix embedded_watcher feature to work with external crates
# Objective
- Make the implementation order consistent between all sources to fit
the order in the trait.
## Solution
- Change the implementation order.